xyz xyz - 1 month ago 15
Java Question

How to handle the fatal exception(bad token exception) in android

This is my code to delete selected item on button click,I added Alert dialog box to this code,After I add this Alert box,Fatal error exception occur.

public class MycustomAdapter extends BaseAdapter implements ListAdapter {
public ArrayList<category> list = new ArrayList<category>();
public Context context;



public MycustomAdapter(ArrayList<category> list, Context context) {
this.list = list;
this.context = context;
}

@Override
public int getCount() {
return list.size();
}

@Override
public Object getItem(int pos) {
return list.get(pos);
}

@Override
public long getItemId(int position) {
return list.get(position).getId();
}


@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.row, null);
}

//Handle TextView and display string from your list
TextView listItemText = (TextView)view.findViewById(R.id.lblreload
);
listItemText.setText(list.get(position).getName());

listItemText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
category row = (category) list.get(position);
int selected_id = row.getId();
String budget = row.getName();

Intent myIntent = new Intent(context, addbudget.class);
myIntent .putExtra("passed data key",budget);
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(myIntent);
}
});

//Handle buttons and add onClickListeners
TextView deleteBtn = (TextView)view.findViewById(R.id.delete_btn);

deleteBtn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
new AlertDialog.Builder(context)
.setTitle("Delete entry")
.setMessage("Are you sure you want to delete this entry?")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
SQLiteDatabase db = new DBhelper(context).getWritableDatabase();
db.delete(DBhelper.TABLE1, DBhelper.C_ID + "=?", new String[] {Integer.toString(list.get(position).getId())});
db.close();
list.remove(position);
notifyDataSetChanged();

}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();

}
});


return view;
}
}


This is the fatal error exception I got when I click the delete button.

22 20:50:56.546 28837-28837/com.example.username.weddingplanning
E/AndroidRuntime﹕ FATAL EXCEPTION: main
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
at android.view.ViewRootImpl.setView(ViewRootImpl.java:811)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:265)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:73)
at android.app.Dialog.show(Dialog.java:282)
at android.app.AlertDialog$Builder.show(AlertDialog.java:951)
at com.example.username.weddingplanning.MycustomAdapter$2.onClick(MycustomAdapter.java:101)
at android.view.View.performClick(View.java:4439)
at android.view.View$PerformClick.run(View.java:18398)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5299)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
at dalvik.system.NativeStart.main(Native Method)


I have already gone through the similar questions in stack overflow,but I didn't get it.I have this delete button in CustomAdapter class,not in Activity class.

Answer

The AlertDialog.Builder needs not just any context to work with, it wants an activity. More precisely, it wants the activity which shows the ListView.

So the question is "how do we get the activity from the context"?

First, you need to initialize your adapter using the activity which contains the ListView:

// assuming 'this' means the activity:
adapter = new MyCustomAdapter(myList, this);

Then you can do the following in the 'getView()' method of 'MyCustomAdapter.java' (let's assume the activity is called 'MyActivity'):

deleteBtn.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v) {

        // you know the condition will be true,
        // but for formal reasons make sure anyway:
        if (context instanceof MyActivity)
        {
            new AlertDialog.Builder((MyActivity)context)
                    .setTitle("Delete entry")
                    .setMessage("Are you sure you want to delete this entry?")
                    .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                     // and so on...
                    })
                    .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            // do nothing
                        }
                    })
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .show();

        }
     }
});

To be on the safe side with the database call, one could still write

SQLiteDatabase db = new DBhelper(context.getApplicationContext()).getWritableDatabase();