-1

I have a RecyclerView that displays twitter like posts. Each list item has a little heart you can press to "Like" the post.

The way it works is that clicking on a heart icon launches an IntentService which makes the API call. The API then returns a status code (e.g. liked_successfully).

My issue is that I want to disable that little heart icon while the API call is being made. I can disable it when the user clicks on it by setting that up in the Adapter but enabling it again is what I do not know how to do.

My IntentService can broadcast the result to all registered BroadcastReceivers. I was hoping my Adapter can somehow listen in on that and once more enable the heart icon. But I don't think you can register receivers like that...

Is there some way to solve my problem?

EDIT: Thanks to the help of ankit aggarwal's answer I was able to solve my problem. Here is what I did (Note, I chose to go with the BroadcastReceiver though you could do this the same way with the ResultReceiver as ankit suggested):

Step 1: Pass in the adapterPosition to your service inside the onClick() method in your adapter:

public ViewHolder(View view) {
            super(view);
            // Get references to our views          
            heartImageView = (ImageView) view.findViewById(R.id.heartImageView);

            heartImageView.setOnClickListener(new View.OnClickListener(){

                @Override
                public void onClick(View v) {
                    // Get adapter position
                    int adapterPosition = getAdapterPosition();
                    mCursor.moveToPosition(adapterPosition);

                    // Disable your ImageView
                    heartImageView.setClickable(false); 

                    // Start your IntentService, passing in the adapterPosition as an extra
                    //...
            });
       }

Step 2: Have your IntentService return (either via broadcast or otherwise) that adapterPosition to your activity where you get a reference to that row and re-enable the ImageView.

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle extras = intent.getExtras();
        int adapterPosition = extras.getInt(MyService.ADAPTER_POSITION);

        // Re-enable the clicking of the heartImageView for that specific row in RecyclerView
        RecyclerView.ViewHolder holder =
                mRecyclerView.findViewHolderForAdapterPosition(adapterPosition);
        // Get the view from the ViewHolder
        View view = holder.itemView;
        ImageView heartImageView = (ImageView) view.findViewById(R.id.heartImageView);
        // Re-enable the ImageView
        heartImageView.setClickable(true);
        Log.d("MicroR", "heartImageView enabled again for position: " + String.valueOf(adapterPosition));
    }
}
Micro
  • 10,303
  • 14
  • 82
  • 120

2 Answers2

2

Instead of using broadcast receivers, use ResultReceiver so that you can get a callback once your request is done. for implementation check this link. create a method in your adapter class to be called when network call is done. Now from activity you can call the same method in your adapter after receiving the callback.

EDIT: you can use it like this

public class RandomAdapter extends BaseAdapter{
    public void updateAdapter(String <Some value>){
        // Do whatever you want here
    }
}

while creating the adapter, make the object as class level variable so onReceive() of resultReceiver, you can call it like

mAdapter.updateAdapter(<some value>);

If you want to edit your row, you have to get the position of the row item.

ListView list = getListView();
int firstVisibleElement = postListView.getFirstVisiblePosition();
int lastVisibleElement = postListView.getLastVisiblePosition();
if (position >= firstVisibleElement && position <= lastVisibleElement) {
    View view = postListView.getChildAt(position - firstVisibleElement);
    // now get your like imageview from view and do whatever you want to do with it
}
Community
  • 1
  • 1
Ankit Aggarwal
  • 5,317
  • 2
  • 30
  • 53
  • Maybe what I should be asking you then is how do you create a method in your adapter class that can be called by the Activity/Fragment that receives results via ResultReceiver? – Micro Feb 21 '16 at 05:12
  • Thank you for the update. But that leads me to another question: How can I enable/disable the ImageView in that specific row in `mAdapter.updateAdapter()`? I could pass in the Cursor ID to `updateAdapter()`, but after that..? – Micro Feb 21 '16 at 05:26
  • Don't pass the cursor id. just pass the item position. Check the updated solution – Ankit Aggarwal Feb 21 '16 at 05:58
  • Well I am using a `RecyclerView`.. So I could pass in the item position back to the adapter. But once inside the adapter I am not sure what to do with that item position - that is how can I get the ImageView based on that item position inside the adapter...? – Micro Feb 21 '16 at 06:10
  • 1
    What I would suggest you is don't do this view updation part inside adapter just do it inside your activity. You can change it by View view = postListView.getChildAt(position - firstVisibleElement); ImageView img = view.findViewById(R.id.your_drawable_id); img.setImageResource(); Here variable position denotes the position of the list item to be edited – Ankit Aggarwal Feb 21 '16 at 06:12
  • Ah, very clever. I updated my question to reflect the implementation that worked for me. Your answer was invaluable!! – Micro Feb 21 '16 at 07:14
0

You can use a publisher/subscriber library like EventBus for achieving such functionality. Simply you can follow this tutorial for getting a grasp on that.

Farhad
  • 12,178
  • 5
  • 32
  • 60