How to return AlertDialogs from a generic class in Android?
Within a public class that doesn't extend any other class I'm doing some evaluation stuff and I would like to return a Dialog if something needs to be communicated to the user.
I'm using an AsyncTask to run a method of an instance of this class from the main UI:
private O开发者_JAVA技巧nlineActivities onlineActivities = new OnlineActivities();
new DoOnlineActivity().execute(getApplicationContext());
private class DoOnlineStuff extends AsyncTask<Context, Integer, Dialog> {
@Override
protected Dialog doInBackground(Context... params) {
return onlineActivities.start(params[0]);
}
@Override
protected void onProgressUpdate(Integer... progress) {
Log.v(RuntimeVars.getMyName(), "AsyncOnlineTask in progess");
}
@Override
protected void onPostExecute(Dialog result) {
if (result != null)
result.show();
}
}
Now, the public Dialog start()
method of OnlineActivities.java
creates a dialog using the Context that was assigned via it's parameter.
When the Dialog is returned to onPostExecute
I receive the following exception
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): FATAL EXCEPTION: main
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.view.ViewRoot.setView(ViewRoot.java:509)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.app.Dialog.show(Dialog.java:241)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at info.myProject.messaging.ConversationList$DoOnlineActivity.onPostExecute(ConversationList.java:245)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at info.myProject.messaging.ConversationList$DoOnlineActivity.onPostExecute(ConversationList.java:1)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.os.AsyncTask.finish(AsyncTask.java:417)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.os.AsyncTask.access$300(AsyncTask.java:127)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.os.Handler.dispatchMessage(Handler.java:99)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.os.Looper.loop(Looper.java:123)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at android.app.ActivityThread.main(ActivityThread.java:4627)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at java.lang.reflect.Method.invokeNative(Native Method)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at java.lang.reflect.Method.invoke(Method.java:521)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
11-14 23:53:43.303: ERROR/AndroidRuntime(1320): at dalvik.system.NativeStart.main(Native Method)
I suppose I cannot use the context like this. But what would be the alternative? How can I outsource some basic stuff I always need to do, even some general Dialogs?
Do I need to use custom intents instead?
Don't do this. Pass the context into the constructor. And then show the activity before you go into do in background and then clear it after.
new DoOnlineActivity().execute(getApplicationContext());
private class DoOnlineStuff extends AsyncTask<Void, Integer, Dialog> {
Context ctx;
Dialog dialg
public DoOnlineStuff(Context ctx){
this.ctx = ctx;
}
@Override
protected void onPreExecute(){
dialg = createdialog;
dialog.show()
}
@Override
protected Dialog doInBackground(Void... void) {
// Do stuff in background
publishProgress(0);
}
@Override
protected void onProgressUpdate(Integer... progress) {
Log.v(RuntimeVars.getMyName(), "AsyncOnlineTask in progess");
}
@Override
protected void onPostExecute(Dialog result) {
dialog.dismiss()
}
I got a part of it to work. The problem was the usage of getApplicationContext()
. The Android SDK states
Return the context of the single, global Application object of the current process.
I suppose this context differs from the context of the actual activity.
So, the Dialog gets displayed when I use this
instead of getApplicationContext()
:
private OnlineActivities onlineActivities = new OnlineActivities();
new DoOnlineActivity(this).execute();
private class DoOnlineStuff extends AsyncTask<Void, Integer, Dialog> {
Context ctx;
Dialog dialog;
public DoOnlineActivity(Context ctx){
this.ctx = ctx;
}
@Override
protected Dialog doInBackground(Void... params) {
return onlineActivities.start(ctx);
}
@Override
protected void onProgressUpdate(Integer... progress) {
Log.v(RuntimeVars.getMyName(), "AsyncOnlineTask in progess");
}
@Override
protected void onPostExecute(Dialog result) {
if (result != null) {
dialog = result;
dialog.show();
}
}
}
BUT: Now the button I created within the Dialog won't do anything. I guess the OnClickListener()
within my Dialog isn't responsive in the context of my main ui:
final View layout = View.inflate(ctx, R.layout.dialog_phonenumber_request, null);
((TextView) layout.findViewById(R.id.label)).setText(ctx.getString(R.string.dialog_insert_self_phonenumber_request_text1));
final EditText savedPhoneNumber = ((EditText) layout.findViewById(R.id.phonenum));
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setIcon(0);
builder.setTitle(ctx.getString(R.string.dialog_insert_self_phonenumber_request_title));
builder.setPositiveButton(ctx.getString(R.string.save),
new Dialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
String toSavePhoneNumber = savedPhoneNumber.getText().toString().trim();
Database thisDBHandler = new Database(ctx);
thisDBHandler.open();
thisDBHandler.insertSetting(RuntimeVars.getDBPhoneNumberName(), toSavePhoneNumber);
thisDBHandler.close();
}
}
);
builder.setView(layout);
return builder.create();
So the last step should be to tell the OnClickListener()
which context to use. But how can this be done? new Dialog.OnClickListener()
won't take any parameter about the context?
Thanks!
S.
精彩评论