Search code examples
androidlistviewparse-platform

Getting Parse Object ID from onListItemClick


I am currently working on an app which contains a friends list when logged in and user profiles. When the user clicks on a friend in the friends list, I would like them to be directed to a profile page for this friend. To do this, I have been trying to extract the specific object id from the user that is clicked on in the list view and then pass that onto the next activity where I use it to run a query for all the users other attributes (name, email, hometown, etc.). I have figured out how to pass along data through intents but I am having all sorts of trouble obtaining the user id from the list item clicked. My onItemCLick code is below.

```

public void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);

    ParseObject item = (ParseObject) l.getAdapter().getItem(position);
    String objectID = item.getObjectId().toString();

    Intent intent = new Intent(getActivity(), FriendsProfileActivity.class);
    intent.putExtra("ID", objectID);
    startActivity(intent);

```

I have also tried something of this sort to not avail.

```

public void onListItemClick(ListView l, View v, int position, long id) {
     super.onListItemClick(l, v, position, id);

     ParseObject item = (ParseObject) l.getAdapter().getItem(position);
     item.saveInBackground(new SaveCallback() {
         @Override
         public void done(ParseException e) {
             if(e == null) {
                 String objectID = item.getObjectId();
                 Log.e(TAG, objectID);

                 Intent intent = new Intent(getActivity(), FriendsProfileActivity.class);
                 intent.putExtra("ID", objectID);
                 startActivity(intent);
                }
                else {
                    Log.e(TAG, e.getMessage());
                }
            }
        });

    }

```

In both cases, the app crashes when I click on the user in the list view. How can I succesfully pull the object ID from the user clicked on and pass it along?

Edit: Here is the logcat error.

Process: com.richluick.ribbit, PID: 2194 java.lang.ClassCastException: java.lang.String cannot be cast to com.parse.ParseObject at com.richluick.ribbit.FriendsFragment.onListItemClick(FriendsFragment.java:83) at android.support.v4.app.ListFragment$2.onItemClick(ListFragment.java:58) at android.widget.AdapterView.performItemClick(AdapterView.java:299) at android.widget.AbsListView.performItemClick(AbsListView.java:1113) at android.widget.AbsListView$PerformClick.run(AbsListView.java:2904) at android.widget.AbsListView$3.run(AbsListView.java:3638) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5017) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) at dalvik.system.NativeStart.main(Native Method)

Edit: Here is the full code for the activity including the query and list adapter. package com.richluick.ribbit;

import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.ParseQuery;
import com.parse.ParseRelation;
import com.parse.ParseUser;
import com.parse.SaveCallback;

import java.util.List;

public class FriendsFragment extends android.support.v4.app.ListFragment {

    public static final String TAG = FriendsFragment.class.getSimpleName();

    protected List<ParseUser> mFriends;
    protected ParseRelation<ParseUser> mFriendsRelation;
    protected ParseUser mCurrentUser;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_friends, container, false);
        return rootView;
    }

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

        mCurrentUser = ParseUser.getCurrentUser();
        mFriendsRelation = mCurrentUser.getRelation(ParseConstants.KEY_FRIENDS_RELATION);

        getActivity().setProgressBarIndeterminateVisibility(true);

        ParseQuery<ParseUser> query =  mFriendsRelation.getQuery();
        query.addAscendingOrder(ParseConstants.KEY_USERNAME);
        query.findInBackground(new FindCallback<ParseUser>() {
            @Override
            public void done(List<ParseUser> friends, ParseException e) {
                getActivity().setProgressBarIndeterminateVisibility(false);

                if (e == null) {
                    mFriends = friends;

                    String[] usernames = new String[mFriends.size()];
                    int i = 0;
                    for (ParseUser user : mFriends) {
                        usernames[i] = user.getUsername();
                        i++;
                    }
                    ArrayAdapter<String> adapter = new ArrayAdapter<String>(getListView().getContext(),
                    android.R.layout.simple_list_item_1, usernames);
                    setListAdapter(adapter);
                }
                else {
                    Log.e(TAG, e.getMessage());
                    AlertDialog.Builder builder = new AlertDialog.Builder(getListView().getContext());
                    builder.setTitle(R.string.error_title)
                            .setMessage(e.getMessage())
                            .setPositiveButton(android.R.string.ok, null);
                    AlertDialog dialog = builder.create();
                    dialog.show();
                }
            }
        });
    }

    @Override
  public void onListItemClick(ListView l, View v, int position, long id) {
     super.onListItemClick(l, v, position, id);

        final ParseObject item = (ParseObject) l.getAdapter().getItem(position);
        item.saveInBackground(new SaveCallback() {
            @Override
            public void done(ParseException e) {
                if(e == null) {
                    String objectID = item.getObjectId();
                    Log.e(TAG, objectID);

                    Intent intent = new Intent(getActivity(), FriendsProfileActivity.class);
                    intent.putExtra("ID", objectID);
                    startActivity(intent);
                }
                else {
                    Log.e(TAG, e.getMessage());
                }
            }
        });

}

}


Solution

  • Have a look at ParseQueryAdapter

    Docs: https://parse.com/docs/android_guide#ui-queryadapter

    Tutorial: https://parse.com/tutorials/parse-query-adapter

    API: https://parse.com/docs/android/api/com/parse/ParseQueryAdapter.html.

    Also I would recommend EventBus to pass the ParseObject to the next Activity https://github.com/greenrobot/EventBus.

    Then you can do:

    Adapter:

    Intent intent = new Intent(getActivity(), FriendsProfileActivity.class);
    EventBus.getDefault().postSticky(YourParseObject);
    startActivity(intent);
    

    Anywhere in FriendsProfileActivity:

    ParseObject yourParseObject = EventBus.getDefault().getStickyEvent(ParseObject.class);
    

    If you move on to using subclasses in parse.com, then any subclass can be sent via the EventBus this way.

    Example code - untested but should be close to what you want

    The ParseQueryAdapter:

    The layout for R.layout.adapter_item_friend - can be customized but nothing fancy here

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:paddingTop="5dp">
    
    
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:text="item" />
    
    </RelativeLayout>
    

    The Adapter:

    public class ParseUserFriendsAdapter extends ParseQueryAdapter<ParseUser> {
    
        private static final String TAG = ParseUserFriendsAdapter.class.getSimpleName();
    
        public ParseUserFriendsAdapter(Context context) {
            super(context, new ParseQueryAdapter.QueryFactory<ParseUser>() {
    
                @Override
                public ParseQuery<ParseUser> create() {
                    ParseUser currentUser = ParseUser.getCurrentUser();
                    ParseRelation<ParseUser> friendsRelation = currentUser.getRelation(ParseConstants.KEY_FRIENDS_RELATION);
                    ParseQuery<ParseUser> query =  friendsRelation.getQuery();
                    query.addAscendingOrder(ParseConstants.KEY_USERNAME);
                    return query;
                }
            });
        }
    
        @InjectView(R.id.text) TextView text;
    
        @Override
        public View getItemView(final ParseUser user, View v, ViewGroup parent) {
    
            if (v == null) {
                v = View.inflate(getContext(), R.layout.adapter_item_friend,
                        null);
            }
    
            super.getItemView(user, v, parent);
    
            ButterKnife.inject(this, v);
    
            text.setText(user.getUsername());
    
    
            return v;
    
        }
    
    }
    

    I am using a regular fragment containing a ListView in it's layout:

    R.layout.yourfriendslistlayout:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:choiceMode="singleChoice"
            android:dividerHeight="1dp" />
    
    </LinearLayout>
    

    The important parts of the code in the fragment:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate");
    
        mAdapter = new ParseUserFriendsAdapter(getActivity());
    
        super.onCreate(savedInstanceState);
    }
    
    @InjectView(R.id.listview) ListView mListView;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(
                R.layout.yourfriendslistlayout, container, false);
    
        ButterKnife.inject(this, rootView);
    
        /** Setting the list adapter for the ListFragment */
        mListView.setAdapter(mAdapter);
        mListView.setOnItemClickListener(new OnItemClickListener() {
    
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
    
                // Now it is easy to get the ParseObject that is clicked
                ParseUser friend = mAdapter.getItem(position);
    
                Toast.makeText(getActivity(), "clicked " + friend.getObjectId(), Toast.LENGTH_SHORT).show();
    
                EventBus.getDefault().postSticky(friend);
    
                Intent intent = new Intent(getActivity(),
                        FriendsProfileActivity.class);
                startActivity(intent);
    
            }
        });
        return rootView;
    }
    

    Optional addition to the fragment code:

    /* 
     *This last part automatically sets the load indicator whenever parse performs a query 
     */
    private final OnQueryLoadListener<ParseUser> queryListener = new OnQueryLoadListener<ParseUser>() {
    
        @Override
        public void onLoaded(List<ParseUser> arg0, Exception arg1) {
            getActivity().setProgressBarIndeterminateVisibility(Boolean.FALSE);
        }
    
        @Override
        public void onLoading() {
            getActivity().setProgressBarIndeterminateVisibility(Boolean.TRUE);
        }
    };
    
    @Override
    public void onResume() {
        mAdapter.addOnQueryLoadListener(queryListener);
        super.onResume();
    }
    
    @Override
    public void onPause() {
        mAdapter.removeOnQueryLoadListener(queryListener);
        super.onPause();
    }