Reputation: 746
I have a problem with showing a MaterialDialog i've created in my RecyclerView Adapter. I want to show the dialog in the activity the recycler view is in and i have passed the activity context but it always gives me this exception :
com.afollestad.materialdialogs.MaterialDialog$DialogException: Bad window token, you cannot show a dialog before an Activity is created or after it's hidden.
Here is my RecyclerView Adapter :
public class AssetsAdapter extends RecyclerView.Adapter<AssetsAdapter.ItemHolder>{
private static final String TAG = "AssetsAdapter";
private ArrayList<Asset> listData;
private Context activityContext;
private MaterialDialog dialog;
public AssetsAdapter(ArrayList<Asset> listData, Context activityContext, UserService userService) {
this.listData = listData;
this.activityContext = activityContext;
}
public AssetsAdapter(Context activityContext) {
this.activityContext = activityContext;
}
@NonNull
@Override
public ItemHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout_item_assets, parent, false);
return new ItemHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ItemHolder holder, final int position) {
holder.tv_name.setText(listData.get(position).getName());
holder.tv_manufacturer.setText(listData.get(position).getAsset_id());
holder.tv_quantity.setText(listData.get(position).getPurchase_cost());
holder.btn_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showCreateDialog(position);
}
});
holder.btn_edit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(activityContext, "Edit", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
if(listData.isEmpty()) return 0;
else return listData.size();
}
public class ItemHolder extends RecyclerView.ViewHolder{
private ImageView iv_asset;
private TextView tv_name;
private TextView tv_manufacturer;
private TextView tv_quantity;
private TextView tv_status;
private ImageButton btn_edit;
private ImageButton btn_delete;
public ItemHolder(View itemView) {
super(itemView);
iv_asset = itemView.findViewById(R.id.iv_asset);
tv_name = itemView.findViewById(R.id.tv_name);
tv_manufacturer = itemView.findViewById(R.id.tv_manufacturer);
tv_quantity = itemView.findViewById(R.id.tv_quantity);
tv_status = itemView.findViewById(R.id.tv_status);
btn_edit = itemView.findViewById(R.id.btn_edit);
btn_delete = itemView.findViewById(R.id.btn_delete);
}
}
private void showCreateDialog(final int id){
Log.i(TAG, "showCreateDialog: called");
MaterialDialog.Builder builder = new MaterialDialog.Builder(activityContext)
.content("Are you sure you want to delete this data?")
.contentGravity(GravityEnum.CENTER)
.autoDismiss(true)
.positiveText("Yes")
.negativeText("No")
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
//deleteAsset(id);
}
})
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
// do nothing
}
})
.canceledOnTouchOutside(true);
dialog = builder.build();
dialog.show();
}
}
I think i have passed the context correctly since i have no problem of showing toasts. So i'm not sure what i did wrong. Any answer would be appreciated, thank you.
Upvotes: 1
Views: 1064
Reputation: 1855
Because you're using dialog view inside your adapter. Don't made actions inside adapter like clickListeners. Use interface to do click actions.
Inside adapter add click listener
var mItemClickListener: MyCallback? = null
fun setOnClickListener(click: MyCallback) {
mItemClickListener = click
}
MyCallback
public interface MyCallback {
void onListClick(int position, Object _list);
}
Click actions inside adapter
holder.btn_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mItemClickListener.onListClick(getAdapterPosition(), yourItemModel)
}
});
Activity/Fragment
MyAdapter myAdapter = new MyAdapter()
recyclerView.setAdapter(myAdapter)
myAdapter.setOnClickListener(new MyCallback(){
@Override
public void onListClick(Int position, Item yourItem) {
//here you can show dialog
showDialog()
}
})
Hope this help you :)
Upvotes: 1
Reputation: 1550
You can use EventBus
In your gradle file
dependencies {
implementation 'org.greenrobot:eventbus:3.1.1'
}
In onBindViewHolder
holder.btn_delete.setTag(holder);
holder.btn_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ItemHolder myItemHolder = (ItemHolder) v.getTag();
EventBus.getDefault().post(listData.get(myItemHolder.getAdapterPosition()));
}
});
In Activity
@Override
protected void onStart () {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop () {
super.onStop();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void deleteAssetEvent (Asset asset){
//Call your dialog here
}
Upvotes: 1
Reputation: 907
Use the interface like this in your adapter
public class AssetsAdapter extends RecyclerView.Adapter<AssetsAdapter.ItemHolder>{
private static final String TAG = "AssetsAdapter";
private OnButtonClickListener listener;
...........
..........
.........
public AssetsAdapter(ArrayList<Asset> listData, Context activityContext, UserService userService,OnButtonClickListener listener) {
this.listData = listData;
this.activityContext = activityContext;
this.listener = listener;
}
.......
......
...
..
@Override
public void onBindViewHolder(@NonNull ItemHolder holder, final int position) {
holder.tv_name.setText(listData.get(position).getName());
holder.tv_manufacturer.setText(listData.get(position).getAsset_id());
holder.tv_quantity.setText(listData.get(position).getPurchase_cost());
holder.btn_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.showCreateDialog();
}
});
holder.btn_edit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(activityContext, "Edit", Toast.LENGTH_SHORT).show();
}
});
}
Create the interface like
public interface OnButtonClickListener {
void showCreateDialog();
}
Implement the interface in your activity and create the material dialog in the implementation of that method.
Upvotes: 2