Android: Show dialog without activity context

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;

/**
* Created by nhancao on 10/31/16.
*/

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();
One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.