Dialog is built by ui context. The approach to show dialog without ui context (activity) in some case: call dialog in rest api, show dialog after own activity finish, call dialog in first activity and want to show it in the next activity also.
First: use Broadcast receiver
Assume: We call open dialog after delay timeout and run TestActivity concurrently in MainActivity.
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import java.util.HashMap;
public class Alerts {
public static void register(Activity activity) {
AlertReceiver.register(activity);
}
public static void unregister(Activity activity) {
AlertReceiver.unregister(activity);
}
public static void displayError(Context context, String msg) {
Intent intent = new Intent("MyApplication.INTENT_DISPLAYERROR");
intent.putExtra(Intent.EXTRA_TEXT, msg);
context.sendOrderedBroadcast(intent, null);
}
private static void displayErrorInternal(Context context, String msg) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Error").setMessage(msg).setCancelable(false).setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
final AlertDialog alert = builder.create();
alert.show();
}
private static class AlertReceiver extends BroadcastReceiver {
private static HashMap<Activity, AlertReceiver> registrations;
static {
registrations = new HashMap<Activity, AlertReceiver>();
}
private Context activityContext;
private AlertReceiver(Activity activity) {
activityContext = activity;
}
static void register(Activity activity) {
AlertReceiver receiver = new AlertReceiver(activity);
activity.registerReceiver(receiver, new IntentFilter("MyApplication.INTENT_DISPLAYERROR"));
registrations.put(activity, receiver);
}
static void unregister(Activity activity) {
AlertReceiver receiver = registrations.get(activity);
if (receiver != null) {
activity.unregisterReceiver(receiver);
registrations.remove(activity);
}
}
@Override
public void onReceive(Context context, Intent intent) {
abortBroadcast();
String msg = intent.getStringExtra(Intent.EXTRA_TEXT);
displayErrorInternal(activityContext, msg);
}
}
}
In MainActivity
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Alerts.displayError(getApplicationContext(), "test Error");
}
}, 500);
startActivity(new Intent(this, TestActivity.class));
finish();
In TestActivity or any activity want to show this dialog
@Override
protected void onResume() {
super.onResume();
Alerts.register(this);
}
@Override
protected void onPause() {
Alerts.unregister(this);
super.onPause();
}
Make sure declare 2 activity in AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity_">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".TestActivity"/>
</application>
Another way: Use permission
Just add this before your alertDialog.show();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
and use this permission:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
And now, you can use applicationContext() for dialog builder
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext());
builder.setTitle("Error").setMessage("test").setCancelable(false).setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
final AlertDialog alert = builder.create();
alert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alert.show();
}
}, 500);
startActivity(new Intent(this, TestActivity.class));
finish();
Another way: use single context in application and update in each activity (but careful with leak memory, improve it as your way)
You can have a static Context in your Application like this:
public static Context CurrentContext;
and a custom abstract Activity that sets currentContext upon creation like this:
public abstract class CustomActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApplication.CurrentContext = this;
}
}
Then you would get context like this:
AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(MyApplication.CurrentContext);
dlgBuilder.setTitle("Context Example");
dlgBuilder.setMessage("I am being shown from the application Static context!");
dlgBuilder.setNeutralButton("Ok", null);
dlgBuilder.show();