可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to show an Alert Dialog via AlertDialogManager
class to a non-activity
class DeviceAdminReceiverSample
's method onDisabled
, but whenever I call alertDialog
via that method it generates error with following text
Error
06-12 12:01:19.923: E/AndroidRuntime(468): FATAL EXCEPTION: main
06-12 12:01:19.923: E/AndroidRuntime(468): java.lang.RuntimeException: Unable to start
receiver com.android.remotewipedata.DeviceAdminReceiverSample:
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not
for an application
I know the issue is with context
thing but I don't know what to put there so that it work, I tried this
, getApplicationContext()
but all vain. My code for both classes is below
AlertDialogManager
public class AlertDialogManager {
public void showAlertDialog(Context context, String title, String message,
Boolean status) {
final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle(title);
alertDialog.setMessage(message);
if (status != null)
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
alertDialog.show();
}
}
DeviceAdminReceiverSample
public class DeviceAdminReceiverSample extends DeviceAdminReceiver {
static final String TAG = "DeviceAdminReceiver";
AlertDialogManager alert = new AlertDialogManager();
/** Called when this application is no longer the device administrator. */
@Override
public void onDisabled(Context context, Intent intent) {
super.onDisabled(context, intent);
Toast.makeText(context, R.string.device_admin_disabled,
Toast.LENGTH_LONG).show();
// intent.putExtra("dialogMessage", "Device admin has been disabled");
// intent.setClass(context, DialogActivity.class);
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// context.startActivity(intent);
alert.showAlertDialog(context, "Alert",
"Device admin has been disabled", true);
}
回答1:
The problem is 'You can show AlertDialogs from Activity only
'. This is not an issue of context.
Although this is not a good idea to show dialog from receiver (better is to use Notification), But if you want to do so you can create an Activity as dialog and show
回答2:
Just add this before your alertDialog.show();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
or try following is above doesn't works:
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
and use this permission:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
回答3:
If you always want to get the current activity from anywhere in the app you can register an ActivityLifecycleCallback on your Application instance.
Here's an untested implementation that might get you closer.
public class TestApp extends Application {
private WeakReference<Activity> mActivity = null;
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mActivity = new WeakReference<Activity>(activity);
}
@Override
public void onActivityDestroyed(Activity activity) {
mActivity.clear();
}
/** Unused implementation **/
@Override
public void onActivityStarted(Activity activity) {}
@Override
public void onActivityResumed(Activity activity) {}
@Override
public void onActivityPaused(Activity activity) {}
@Override
public void onActivityStopped(Activity activity) {}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
});
}
public Activity getCurrentActivity() {
return mActivity.get();
}
}
Then to use this throughout your app you would do some call like this ...
Activity activity = ((TestApp)getApplicationContext()).getCurrentActivity();
The advantages are you can always keep track of your current activity, however its a little too overkill for just handling Dialogs from within the Activity.
回答4:
call this method in activity class
public static void showAlert(Activity activity, String message) {
TextView title = new TextView(activity);
title.setText("Title");
title.setPadding(10, 10, 10, 10);
title.setGravity(Gravity.CENTER);
title.setTextColor(Color.WHITE);
title.setTextSize(20);
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
// builder.setTitle("Title");
builder.setCustomTitle(title);
// builder.setIcon(R.drawable.alert_36);
builder.setMessage(message);
builder.setCancelable(false);
builder.setNegativeButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
回答5:
As AJAY suggested, the best way is to work with the 'Activity' in parameter instead of using the 'context'.
In your personal class, just ask for the activity in its constructor as a mandatory parameter => public void constructorOfTheClass(Activity activity){...}.
When you call the constructor in your Activity, just indicate this parameter and you'll be able to work with it inside the class directly.
Then you can use this 'activity' information in your AlertDialog method within your class as SUNIL noticed to be prompted correctly in the desired Activity.
Hope it helps... and be sure it will work ! ;o)
回答6:
Here's a quick method of properly performing this task that has done the job for me. Basically, what you would do is just create a new thread.
Declare a public and static variable with a type that matches the original activity class.
public static Activity1 activity;
Activity1 is the class that the variable resides in.
- Upon calling the method
onCreate();
, set the variable to be equal to the context of the activity, otherwise known as this.
Example:
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
activity = this;
}
3. Since we now have the context of the activity, we can use it to create a function with an alert dialog by using the
runOnUiThread();
method inside of the function that will call the alert dialog. We would use a
new Runnable()
for the runnable action required for
runOnUiThread();
, and to have the alert dialog actually open, we would override the run function of a runnable item and place the code for the alert dialog in there.
Example function:
public static void exampleDialog(){
Activity1.activity.runOnUiThread(new Runnable){
@Override
public void run(){
//alert dialog code goes here. For the context, use the activity variable from Activity1.
}
}
}
Hope this helps :)
回答7:
Here's what I made and use:
myDialog.java:
import android.app.Activity;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
public class myDialog {
private Activity mActivity;
myDialog(Activity a) {
this.mActivity = a;
}
@SuppressWarnings("InflateParams")
public void build(String title, String msg) {
LayoutInflater inflater = LayoutInflater.from(mActivity);
View subView = inflater.inflate(R.layout.dialog_box_text, null);
final TextView message = subView.findViewById(R.id.message);
message.setText(msg);
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(title);
builder.setView(subView);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
dialog_box_text.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1"
android:orientation="horizontal">
<TextView
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=" "
android:maxLines="1"
android:textColor="@color/colorBlack" />
</LinearLayout>
Example code:
public class MainActivity extends AppCompatActivity {
private myDialog md;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
md = new myDialog(this);
...
md.build("Title", "Message");