初学 Android,请教一个关于 AlertDialog app 库和 support.v7.app 库的问题

2016-07-12 21:17:38 +08:00
 roadna

参考的书籍是《第一行代码》,此书基于 4.x 版本,而我的环境是 AS 2.1.2 , API 23 ,测试手机是 MotoX 2013 , API 22 。在通过广播接收器实现强制用户下线这个功能的时候,出现了一个关于 AlertDialog 的问题。

  1. import android.app.AlertDialog 时: 功能正常,收到广播后弹出 AlertDialog 。

  2. 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 库的解决方法就是参照其中一个答案,但并未触到问题的本质。

不胜感激~

15638 次点击
所在节点    Android
15 条回复
Override
2016-07-12 22:06:00 +08:00
我仿佛又听到有人在背后 @我
roadna
2016-07-12 22:56:07 +08:00
@Override 洗耳恭听
boxgu
2016-07-12 23:18:14 +08:00
onReceive 方法传进来的参数 context, 不能用了生成 AlertDialog.Builder
roadna
2016-07-12 23:41:45 +08:00
@boxgu 那为什么 import android.app.AlertDialog 时又可以呢?我查看了两个库里 Builder 函数的实现是一样的,默认 resolveDialogTheme(context,0), 0 是 theme 的值,会不会是这里存在两个库的差异呢~
wanttofly
2016-07-13 09:46:06 +08:00
也许 http://blog.csdn.net/worst_hacker/article/details/49867043 第 54 条对你有点帮助。
kyze8439690
2016-07-13 10:32:11 +08:00
因为 style 实际数据的获取从 context 中来,你这个 onReceive 的 context 并没有 AppCompat 的 style
roadna
2016-07-13 10:56:12 +08:00
@wanttofly 谢谢!加深了对 context 的理解
bjzhou1990
2016-07-13 14:39:42 +08:00
或者换一种理解方式, AlertDialog 的显示要求你的 App 必须在前台显示,但是收到广播时你的 App 可能已经关掉了, AlertDialog 当然不能显示,所以即使你拿到了正确的 context ,在 onReceiver 里弹 dialog 也是错误的使用方式
roadna
2016-07-13 15:54:21 +08:00
@bjzhou1990 例程里 app 一直处于前台但还是出现了 Alertdialog 打不开的情况,可能是 context 的问题,如 @kyze8439690 所说没有 App Compat style 。广播接收器里弹对话框的确是不推荐的。
roadna
2016-07-15 00:08:53 +08:00
已 Append ,请指教~
@kyze8439690
@bjzhou1990
@wanttofly
@boxgu
wanttofly
2016-07-15 09:16:29 +08:00
6 楼其实已经说的很明白了,我贴的那个链接里也写了啊。。你的 Activity 继承 AppCompatActivity ,所以会包含 v7 包下的 theme ,但是 Application 或者其他的 Context 是不包含的 V7 包的 theme 的,你只要换一下 Context 就好了啊。。。两个库的不同不是你说的那个不同吧。。
kyze8439690
2016-07-15 09:30:49 +08:00
@roadna 也可以试试 ContextThemeWrapper 看看有没有效果
roadna
2016-07-15 11:21:08 +08:00
@wanttofly
BroadcastReciver - 它本身不是 context ,也没有 context 在它里面,但是每当一个新的广播到达的时候,框架都传递一个 context 对象到 onReceive()。这个 context 是一个 ReceiverRestrictedContext 实例。
这是一个文章里写的,见(链接)[http://blog.csdn.net/race604/article/details/9331807]
你的意思是换成 Activity 的 Context ?那样不是会依赖于 activity 处于前台么?
看到比较常见的做法是广播接收器启动一个对话框样式的 activity 。
roadna
2016-07-15 11:31:46 +08:00
@wanttofly
这是两个包的一个对比: http://www.jianshu.com/p/6caffdbcd5db
roadna
2016-07-15 11:41:29 +08:00
@kyze8439690 好的, thx

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/292061

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX