
参考的书籍是《第一行代》,此书基于 4.x 版本,而我的环境是 AS 2.1.2 , API 23 ,测试手机是 MotoX 2013 , API 22 。在通过广播接收器实现强制用户下线这个功能的时候,出现了一个关于 AlertDialog 的问题。
import android.app.AlertDialog 时: 功能正常,收到广播后弹出 AlertDialog 。
import android.support.v7.app.AlertDialog 时(默认引用的库):
在 API 22 的手机中运行,能够收到 Log.d(TAG,"Broadcast received")的日志,但无法生成 AlertDialog 并且程序已停止运行,显示错误为“ Unable to start receiver ...略...You need to use a Theme.AppCompat theme (or descendant) with this activity ”。项目中的 Activity 均继承与 AppCompatActivity ,且 style parent=“ Theme.AppCompat.Light.DarkActionBar ”。
在 API 23 的虚拟器上运行时,无法收到"Broadcast received"日志,但程序不会停止运行。
//build.gradle apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.3" defaultConfig { applicationId "com.roadna.broadcastbestpractice" minSdkVersion 19 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.4.0' } //ForceOfflineReceiver.java package com.roadna.broadcastbestpractice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.support.v7.app.AlertDialog; //import android.app.AlertDialog; import android.util.Log; import android.view.WindowManager; public class ForceOfflineReceiver extends BroadcastReceiver { public static final String TAG = "ForceOfflineReceiver"; @Override public void onReceive(final Context context, Intent intent){ Log.d(TAG, "Broadcast received"); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); dialogBuilder.setTitle("Warning"); dialogBuilder.setMessage("You are forced to be offline. Please try to login again."); dialogBuilder.setCancelable(false); dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which){ ActivityCollector.finishAll(); Intent intent = new Intent(context, LoginActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } }); AlertDialog alertDialog = dialogBuilder.create(); alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); alertDialog.show(); } } 附上 StackOverflow 上一个相关的帖子。更换 android.app.AlertDialog 库的解决方法就是参照其中一个答案,但并未触到问题的本质。
不胜感激~
错误信息:You need to use a Theme.AppCompat theme
修改Builder:AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context,R.style.AlertDialogTheme);
style.xml:<style name="AlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert"></style>
若有错误,请指正~
1 Override 2016-07-12 22:06:00 +08:00 我仿佛又听到有人在背后 @我 |
3 boxgu 2016-07-12 23:18:14 +08:00 via Android onReceive 方法传进来的参数 context, 不能用了生成 AlertDialog.Builder |
4 roadna OP @boxgu 那为什么 import android.app.AlertDialog 时又可以呢?我查看了两个库里 Builder 函数的实现是一样的,默认 resolveDialogTheme(context,0), 0 是 theme 的值,会不会是这里存在两个库的差异呢~ |
5 wanttofly 2016-07-13 09:46:06 +08:00 也许 http://blog.csdn.net/worst_hacker/article/details/49867043 第 54 条对你有点帮助。 |
6 kyze8439690 2016-07-13 10:32:11 +08:00 因为 style 实际数据的获取从 context 中来,你这个 onReceive 的 context 并没有 AppCompat 的 style |
8 bjzhou1990 2016-07-13 14:39:42 +08:00 或者换一种理解方式, AlertDialog 的显示要求你的 App 必须在前台显示,但是收到广播时你的 App 可能已经关掉了, AlertDialog 当然不能显示,所以即使你拿到了正确的 context ,在 onReceiver 里弹 dialog 也是错误的使用方式 |
9 roadna OP @bjzhou1990 例程里 app 一直处于前台但还是出现了 Alertdialog 打不开的情况,可能是 context 的问题,如 @kyze8439690 所说没有 App Compat style 。广播接收器里弹对话框的确是不推荐的。 |
10 roadna OP |
11 wanttofly 2016-07-15 09:16:29 +08:00 6 楼其实已经说的很明白了,我贴的那个链接里也写了啊。。你的 Activity 继承 AppCompatActivity ,所以会包含 v7 包下的 theme ,但是 Application 或者其他的 Context 是不包含的 V7 包的 theme 的,你只要换一下 Context 就好了啊。。。两个库的不同不是你说的那个不同吧。。 |
12 kyze8439690 2016-07-15 09:30:49 +08:00 via Android @roadna 也可以试试 ContextThemeWrapper 看看有没有效果 |
13 roadna OP @wanttofly BroadcastReciver - 它本身不是 context ,也没有 context 在它里面,但是每当一个新的广播到达的时候,框架都传递一个 context 对象到 onReceive()。这个 context 是一个 ReceiverRestrictedContext 实例。 这是一个文章里写的,见(链接)[http://blog.csdn.net/race604/article/details/9331807] 你的意思是换成 Activity 的 Context ?那样不是会依赖于 activity 处于前台么? 看到比较常见的做法是广播接收器启动一个对话框样式的 activity 。 |
14 roadna OP |
15 roadna OP @kyze8439690 好的, thx |