Search code examples
androidandroid-recyclerviewandroid-viewholderonlongclicklistener

ClassCastException in onLongClick of ViewHolder


I'm following this tutorial to implement multi select in my RecyclerView but I have been getting the following runtime exception when I perform a long click:

java.lang.ClassCastException: com.abdralabs.talksee.MyApplication cannot be cast to android.support.v7.app.AppCompatActivity
                                                                       at com.abdralabs.talksee.IMListAdapter$IMListViewHolder.onLongClick(IMListAdapter.java:116)
                                                                       at android.view.View.performLongClick(View.java:5308)
                                                                       at android.view.View$CheckForLongPress.run(View.java:21522)
                                                                       at android.os.Handler.handleCallback(Handler.java:815)
                                                                       at android.os.Handler.dispatchMessage(Handler.java:104)
                                                                       at android.os.Looper.loop(Looper.java:207)
                                                                       at android.app.ActivityThread.main(ActivityThread.java:5740)
                                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
                                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:766)

Activity code:

public class IMListActivity extends AppCompatActivity implements Sertivity{

private RecyclerView recyclerView;
private IMListAdapter imListAdapter;
private List<Chat> chatList = new ArrayList<>();
List<String> stringList;
ActiveChatsDB activeChatsDB;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_imlist);
    Toolbar toolbar = (Toolbar)findViewById(R.id.imlist_toolbar);
    setSupportActionBar(toolbar);
    setBackButtonOnToolbar();

    recyclerView = (RecyclerView)findViewById(R.id.rv_im_list);
    imListAdapter = new IMListAdapter(chatList, getApplicationContext());
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
    recyclerView.setAdapter(imListAdapter);
    prepareChatListData();
}

private void prepareChatListData() {
    String friend;
    String latestMessage;
    activeChatsDB = new ActiveChatsDB(IMListActivity.this);
    stringList = activeChatsDB.getChatList();
    activeChatsDB.close();
    for (int i=0; i<stringList.size(); i++) {
        friend = stringList.get(i);
        DBAct dbAct = new  DBAct(IMListActivity.this,friend);
        latestMessage = dbAct.getLatestMessage();
        dbAct.close();
        Chat chat = new Chat(friend, latestMessage);
        chatList.add(chat);
    }
    imListAdapter.notifyDataSetChanged();
}

private void setBackButtonOnToolbar(){
    if(getSupportActionBar() != null){
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
    }
}



public RecyclerView getRecyclerView() {
    return recyclerView;
}

}

Adapter code:

public class IMListAdapter extends RecyclerView.Adapter <com.abdralabs.talksee.IMListAdapter.IMListViewHolder> {

private List<Chat> chatList = new ArrayList<Chat>() ;
private Context ctx;
private MultiSelector multiSelector = new MultiSelector();
private ModalMultiSelectorCallback modalMultiSelectorCallback =
        new ModalMultiSelectorCallback(multiSelector) {
            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                if (item.getItemId() == R.id.item_delete) {
                    mode.finish();

                    for (int i = chatList.size(); i >= 0; i--) {
                        if (multiSelector.isSelected(i, 0)) { // (1)
                            // remove item from list
                            ((IMListActivity)ctx).getRecyclerView().getAdapter().notifyItemRemoved(i);
                        }
                    }

                    multiSelector.clearSelections(); // (2)
                    return true;

                }
                return false;
            }

            @Override
            public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
                super.onCreateActionMode(actionMode, menu);
                ((AppCompatActivity)ctx).getMenuInflater().inflate(R.menu.contextual_menu_friends, menu);
                return true;
            }
        };

public IMListAdapter(List<Chat> chatList, Context ctx){
    this.chatList = chatList;
    this.ctx = ctx;
}


@Override
public com.abdralabs.talksee.IMListAdapter.IMListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_list_row,parent,false);
    return new com.abdralabs.talksee.IMListAdapter.IMListViewHolder(itemView, chatList, ctx);    }

@Override
public void onBindViewHolder(com.abdralabs.talksee.IMListAdapter.IMListViewHolder holder, int position) {
    Chat chat = chatList.get(position);
    holder.name.setText(chat.getName());
    holder.recentMsg.setText(chat.getRecentMessage());
}

@Override
public int getItemCount() {
    return chatList.size();
}

public class IMListViewHolder extends SwappingHolder implements View.OnClickListener, View.OnLongClickListener{
    public TextView name;
    public TextView recentMsg;
    List<Chat> chatList = new ArrayList<Chat>();
    Context ctx;

    public IMListViewHolder(View itemView, List<Chat> chatList, Context ctx) {
        super(itemView, multiSelector);
        this.chatList = chatList;
        this.ctx = ctx;
        itemView.setOnClickListener(this);
        itemView.setOnLongClickListener(this);
        itemView.setLongClickable(true);
        name = (TextView) itemView.findViewById(R.id.name_chat);
        recentMsg = (TextView)itemView.findViewById(R.id.tv_recent_msg_im_list);
    }

    @Override
    public void onClick(View v) {
        int position = getAdapterPosition();
        Chat chat = this.chatList.get(position);
        Intent intent = new Intent(this.ctx, IMActivity.class);
        intent.putExtra("otherUserName",chat.getName());
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        this.ctx.startActivity(intent);


    }

    @Override
    public boolean onLongClick(View v) {
        if (!multiSelector.isSelectable()) { // (3)
            ((AppCompatActivity)ctx).startSupportActionMode(modalMultiSelectorCallback);
            multiSelector.setSelectable(true); // (4)
            multiSelector.setSelected(com.abdralabs.talksee.IMListAdapter.IMListViewHolder.this, true); // (5)
            return true;
        }
        return false;
    }
}

}

I don't know how I'm supposed to peform the right type casting. Please help.

EDIT 1:

I tried replacing the onLongClick code to

public boolean onLongClick(View v) {
        if (!multiSelector.isSelectable()) { // (3)
            ((IMListActivity)ctx).startSupportActionMode(modalMultiSelectorCallback);
            multiSelector.setSelectable(true); // (4)
            multiSelector.setSelected(IMListViewHolder.this, true); // (5)
            return true;
        }
        return false;
    }

as Sachin Bahukhandi suggested, but I'm getting the same error

java.lang.ClassCastException: com.abdralabs.talksee.MyApplication cannot be cast to com.abdralabs.talksee.IMListActivity
                                                                     at com.abdralabs.talksee.IMListAdapter$IMListViewHolder.onLongClick(IMListAdapter.java:116)
                                                                     at android.view.View.performLongClick(View.java:5308)
                                                                     at android.view.View$CheckForLongPress.run(View.java:21522)
                                                                     at android.os.Handler.handleCallback(Handler.java:815)
                                                                     at android.os.Handler.dispatchMessage(Handler.java:104)
                                                                     at android.os.Looper.loop(Looper.java:207)
                                                                     at android.app.ActivityThread.main(ActivityThread.java:5740)
                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:766)

In the tutorial that I'm following the code is as such:

@Override
public boolean onLongClick(View view) {
    if (!mMultiSelector.isSelectable()) {
        ((AppCompatActivity) getActivity()).startSupportActionMode(mActionModeCallback); // (2)
        mMultiSelector.setSelectable(true);
        mMultiSelector.setSelected(MyViewHolder.this, true);
        return true;
    }
    return false;
}

In the above code getActivity is called somehow from the Viewholder and type casted to AppCompatActivity. I don't know how to call getActivity directly from the ViewHolder since I'm getting and error so I tried to type cast a context object (which was passed from my Activity through the adapter constructor) to AppCompatActivity. So I don't exactly know what I'm doing wrong here.


Solution

  • So I solved this by passing the activity reference to the constructor of the adapter and calling

    imListActivity.startSupportActionMode(modalMultiSelectorCallback);
    

    instead of doing this

    ((IMListActivity)ctx).startSupportActionMode(modalMultiSelectorCallback);