参考的书籍是《第一行代码》,此书基于 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
|