HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavaMinor

Using an Adapter with Parse query in Android

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
androidwithqueryparseadapterusing

Problem

I'm an iOS developer new to Android. I'm creating my first Android app and I have several questions. My app uses Android Studio, gradle, and it's based on Parse (the backend). Basically, takes messages from the backend and shows them. User has the possibility to delete them, or click them and see the detail, and of course unread messages have a different color.

This is the code of one class, called MessagesListFragment.java, after that a few questions.

```
package com.ricardoruizlopez.xxxxx.messages;

import ...

public class MessagesListFragment extends Fragment {

private static final String LOG_TAG = "MessagesListFragment";
MessagesAdapter mAdapter;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

View v = inflater.inflate(R.layout.messages_list_layout, container, false);
final ListView listView = (ListView) v.findViewById(R.id.list);

// load messages and attach them to the list
ParseQuery messagesQuery= ParseQuery.getQuery(Message.class);
messagesQuery.whereEqualTo("receiver", ParseUser.getCurrentUser());
messagesQuery.whereEqualTo("deleted", false);
messagesQuery.include("sender");
messagesQuery.orderByDescending("createdAt");
messagesQuery.setLimit(1000);
final ProgressDialog progress = ProgressDialog.show(getActivity(), null, getString(R.string.MESSAGES_TABLE_VIEW_CONTROLLER_LOADING_MESSAGES));
messagesQuery.findInBackground(new FindCallback() {
@Override
public void done(List list, ParseException e) {
progress.dismiss();
if (e == null) {
mAdapter = new MessagesAdapter(list);
listView.setAdapter(mAdapter);

} else {
Log.d(LOG_TAG, "Error loading messages. " + e.getLocalizedMessage());
new AlertDialog.Builder(getActivity())
.setTitle(R.string.ALERT_VIEW_ERROR)
.setMessage(R.string.MESSAGE

Solution

MessagesListFragment

Firstly, onCreateView should only be used for initializing the view.
If you want to perform networks calls, you may do so in onResume():

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.messages_list_layout, container, false);
    final ListView listView = (ListView) v.findViewById(R.id.list);

    listView.setOnItemClickListener(mMessageItemClickListener);

    return v;
}

@Override
public void onResume(){
  super.onResume();

  requestMessages();
}

private void requestMessages(){

  ParseQuery messagesQuery= ParseQuery.getQuery(Message.class);

  messagesQuery.whereEqualTo("receiver", ParseUser.getCurrentUser());
  messagesQuery.whereEqualTo("deleted", false);
  messagesQuery.include("sender");
  messagesQuery.orderByDescending("createdAt");
  messagesQuery.setLimit(1000);

  final ProgressDialog progress = ProgressDialog.show(getActivity(), null, getString(R.string.MESSAGES_TABLE_VIEW_CONTROLLER_LOADING_MESSAGES));
  messagesQuery.findInBackground(mFindCallback);

}


For long listeners and callbacks, I usually prefer to make them member variables:

public class MessagesListFragment extends Fragment  {

  //...

  private FindCallback mFindCallback = new FindCallback(){

    @Override
    public void done(List list, ParseException e) {
        progress.dismiss();
        if (e == null) {
            listView.setAdapter(new MessagesAdapter(list));

        } else {
            Log.d(LOG_TAG, "Error loading messages. " + e.getLocalizedMessage());
            new AlertDialog.Builder(getActivity())
                    .setTitle(R.string.ALERT_VIEW_ERROR)
                    .setMessage(R.string.MESSAGES_TABLE_VIEW_CONTROLLER_ERROR_LOADING_MESSAGES)
                    .setPositiveButton(R.string.ALERT_VIEW_OK, null)
                    .show();
        }
    }

  };
}


Note that it is almost never necessary to make an adapter a member variable.
Once you've assigned an adapter, you can access it from the ListView using getAdapter()

private AdapterView.OnItemClickListener mMessageItemClickListener = new AdapterView.OnItemClickListener(){

  @Override
  public void onItemClick(AdapterView parent, View view, int position, long id) {
      Log.d(LOG_TAG, "onItemClick");
      Message message = (Message) mListView.getItemAtPosition(position);

      // mark message as read if needed
      if (message.getUnread()) {
          message.setUnread(false);
          mAdapter.notifyDataSetChanged();
          message.saveInBackground();
      }

      // show message detail
      Intent messageDetail = new Intent(getActivity(), MessageDetailActivity.class);
      messageDetail.putExtra("message",messageDetail)
      startActivity(messageDetail);
  }

}


Previously, your code had the following line:
MessageDetailActivity.message = message;
Unfortunately, things aren't as simple on Android as they are on iOS. Kindly follow this tutorial
to understand how data needs to be passed between Activities in Android.

MessagesAdapter

Your adapter implementation is mostly correct albeit one glaring error: It is NOT an Adapter's job to handle click events.
The adapter should only render the list items. Interaction with the items should be handled in the activity or fragment.

Declare an interface to handle button click events in your Adapter

class MessagesAdapter extends BaseAdapter {

  public interface OnMessageDeleteClickListener(){
    void onMessageDeleteClick(Message message, int position, View view);
  }

  private OnMessageDeleteClickListener mDeleteClickListener;

  public MessagesAdapter(List messages,OnMessageDeleteClickListener listener ) {
      mMessages=messages;
      mDeleteClickListener = listener;
  }
}


Set this listener to the delete button in getView()

```
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(getActivity(), R.layout.message_item, null);
}

Message message=mMessages.get(position);
CustomTextView senderTextView = (CustomTextView) convertView.findViewById(R.id.senderTextView);
senderTextView.setText(getString(R.string.MESSAGES_TABLE_VIEW_CONTROLLER_MESSAGE_FROM, message.getSender().getString("displayName")));
CustomTextView dateTextView = (CustomTextView) convertView.findViewById(R.id.dateTextView);
Date createdAt = mMessages.get(position).getCreatedAt();
DateFormat df=DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
dateTextView.setText(df.format(createdAt));

Button deleteButton = (Button) convertView.findViewById(R.id.deleteButton);
deleteButton.setOnClickListener(new View.OnClickListener(){

@Override
public void onClick(View view){
if(mDeleteClickListener != null){
mDeleteClickListener.onMessageDeleteClick(message,position,view);
}

Code Snippets

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.messages_list_layout, container, false);
    final ListView listView = (ListView) v.findViewById(R.id.list);

    listView.setOnItemClickListener(mMessageItemClickListener);

    return v;
}

@Override
public void onResume(){
  super.onResume();

  requestMessages();
}

private void requestMessages(){

  ParseQuery<Message> messagesQuery= ParseQuery.getQuery(Message.class);

  messagesQuery.whereEqualTo("receiver", ParseUser.getCurrentUser());
  messagesQuery.whereEqualTo("deleted", false);
  messagesQuery.include("sender");
  messagesQuery.orderByDescending("createdAt");
  messagesQuery.setLimit(1000);


  final ProgressDialog progress = ProgressDialog.show(getActivity(), null, getString(R.string.MESSAGES_TABLE_VIEW_CONTROLLER_LOADING_MESSAGES));
  messagesQuery.findInBackground(mFindCallback);

}
public class MessagesListFragment extends Fragment  {

  //...

  private FindCallback<Message> mFindCallback = new FindCallback<Message>(){

    @Override
    public void done(List<Message> list, ParseException e) {
        progress.dismiss();
        if (e == null) {
            listView.setAdapter(new MessagesAdapter(list));

        } else {
            Log.d(LOG_TAG, "Error loading messages. " + e.getLocalizedMessage());
            new AlertDialog.Builder(getActivity())
                    .setTitle(R.string.ALERT_VIEW_ERROR)
                    .setMessage(R.string.MESSAGES_TABLE_VIEW_CONTROLLER_ERROR_LOADING_MESSAGES)
                    .setPositiveButton(R.string.ALERT_VIEW_OK, null)
                    .show();
        }
    }

  };
}
private AdapterView.OnItemClickListener mMessageItemClickListener = new AdapterView.OnItemClickListener(){

  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
      Log.d(LOG_TAG, "onItemClick");
      Message message = (Message) mListView.getItemAtPosition(position);

      // mark message as read if needed
      if (message.getUnread()) {
          message.setUnread(false);
          mAdapter.notifyDataSetChanged();
          message.saveInBackground();
      }

      // show message detail
      Intent messageDetail = new Intent(getActivity(), MessageDetailActivity.class);
      messageDetail.putExtra("message",messageDetail)
      startActivity(messageDetail);
  }

}
class MessagesAdapter extends BaseAdapter {

  public interface OnMessageDeleteClickListener(){
    void onMessageDeleteClick(Message message, int position, View view);
  }

  private OnMessageDeleteClickListener mDeleteClickListener;

  public MessagesAdapter(List<Message> messages,OnMessageDeleteClickListener listener ) {
      mMessages=messages;
      mDeleteClickListener = listener;
  }
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = View.inflate(getActivity(), R.layout.message_item, null);
    }

    Message message=mMessages.get(position);
    CustomTextView senderTextView = (CustomTextView) convertView.findViewById(R.id.senderTextView);
    senderTextView.setText(getString(R.string.MESSAGES_TABLE_VIEW_CONTROLLER_MESSAGE_FROM, message.getSender().getString("displayName")));
    CustomTextView dateTextView = (CustomTextView) convertView.findViewById(R.id.dateTextView);
    Date createdAt = mMessages.get(position).getCreatedAt();
    DateFormat df=DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
    dateTextView.setText(df.format(createdAt));

    Button deleteButton = (Button) convertView.findViewById(R.id.deleteButton);
    deleteButton.setOnClickListener(new View.OnClickListener(){

      @Override
      public void onClick(View view){
        if(mDeleteClickListener != null){
          mDeleteClickListener.onMessageDeleteClick(message,position,view);
        }
      }

    });

    // set colors accoring if it's read or not
    CustomTextView fromTextView = (CustomTextView)      
    convertView.findViewById(R.id.fromTextView);

    int color = getResources().getColor(message.getUnread()? R.color.messages_unread : R.color.messages_read);

    senderTextView.setTextColor(color);
    dateTextView.setTextColor(color);
    fromTextView.setTextColor(color);

    return convertView;
  }

Context

StackExchange Code Review Q#93469, answer score: 4

Revisions (0)

No revisions yet.