Search code examples
androidandroid-recyclerviewandroid-intentserviceandroid-broadcastreceiver

Enable/Disable ImageView inside RecyclerView based on network call result


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));
    }
}

Solution

  • 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
    }