在BroadcastReceiver中向Activity添加自定义AlertDialog
在创建AlertDialog时,需要传递一个Context的对象作为参数,但是,这一次并不是在Activity中书写代码,而是在BroadcastReceiver的onReceive(Context context, Intent intent)方法中写,并让AlertDialog在当前获取到焦点的Activity中显示。如果直接用onReceive方法中context作为参数传递给AlertDialog.Builder(),程序会崩溃:
Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
产生的具体原因可以百度。
因此,需要一个Activity的context,所以,创建一个类MyApplication并继承Application,代码如下:
public class MyApplication extends Application { private static Context context; @Override public void onCreate() { super.onCreate(); context = getApplicationContext(); } public static Context getContext() { return context; } }
接着在AndroidManifest.xml文件中进行配置:
<application android:name="com.jiaoji.bluetoothdemo.MyApplication" ... </application>注意:要使用全类名,任何一个项目都只能配置一个Application!!!
那么,创建一个静态注册的BroadcastReceiver,命名为UIReceiver,使用MyApplication.getContext()作为参数进行传递,代码如下:
public class UiReceiver extends BroadcastReceiver { private static AlertDialog progressDialog; private static ProgressBar progressBar; @Override public void onReceive(Context context, Intent intent) { int result = intent.getIntExtra("success", -1); if (result != -1) { switch (result) { case 0: progressBar.clearAnimation(); progressDialog.dismiss(); Toast.makeText(context, "连接失败", Toast.LENGTH_SHORT).show(); break; case 1: progressBar.clearAnimation(); progressDialog.dismiss(); Toast.makeText(context, "连接成功", Toast.LENGTH_SHORT).show(); break; case 2: //正在连接 Animation animation = AnimationUtils.loadAnimation(MyApplication.getContext(), R.anim.rotate_progress); View view = View.inflate(MyApplication.getContext(), R.layout.rotate_dialog, null); progressBar = view.findViewById(R.id.progress); AlertDialog.Builder builder = new AlertDialog.Builder(MyApplication.getContext()); builder.setView(view); progressDialog = builder.create(); progressBar.startAnimation(animation); progressDialog.show(); break; default: Toast.makeText(context, "未知错误", Toast.LENGTH_SHORT).show(); break; } } } }
注意:给全局变量加上static是为了保证onReceive()方法被再次访问时AlertDialog还是原来的对象,另外,创建AlertDialog时的代码位置要注意,如果是写在if语句外面,那么每次访问onReceive()方法时AlertDialog都会被重新创建,最直接的后果是AlertDialog可以显示但关闭不了,因为对象变了!
运行程序,结果崩溃了,还是那个错误!!!
好吧,换个思路。回忆一下,比如,如果在MainActivity中创建AlertDialog时,是不是把MainActivity.this作为参数进行传递,那么,假如当前获得焦点的Activity可以取得,是不是就可以作为参数进行传递了。
创建一个名字为MyActivityManage的类,用来管理获得的Activity,代码如下:
public class MyActivityManager { private static MyActivityManager sInstance = new MyActivityManager(); private WeakReference<Activity> sCurrentActivityWeakRef; private MyActivityManager() { } public static MyActivityManager getInstance() { return sInstance; } public Activity getCurrentActivity() { Activity currentActivity = null; if (sCurrentActivityWeakRef != null) { currentActivity = sCurrentActivityWeakRef.get(); } return currentActivity; } public void setCurrentActivity(Activity activity) { sCurrentActivityWeakRef = new WeakReference<Activity>(activity); } } 然后对MyApplication类进行修改,代码如下:
public class MyApplication extends Application { private static Context context;//视情况而定,是否保留 @Override public void onCreate() { super.onCreate(); context = getApplicationContext(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { MyActivityManager.getInstance().setCurrentActivity(activity); } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } }); } public static Context getContext() { return context; } }接着在对UiReceiver类进行修改,代码如下:
case 2: //正在连接 //获取到目前取得焦点的activity Activity activity = MyActivityManager.getInstance().getCurrentActivity(); Animation animation = AnimationUtils.loadAnimation(activity, R.anim.rotate_progress); View view = View.inflate(activity, R.layout.rotate_dialog, null); progressBar = view.findViewById(R.id.progress); AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setView(view); progressDialog = builder.create(); progressBar.startAnimation(animation); progressDialog.show(); break;再次运行,终于成功了。