Dialog样式的Activity-可以在任何地方弹出的Dialog

最近项目用到一个需求,当收到透传消息后不管在哪个界面都要弹出一个dialog,当时觉得这还不简单嘛,new一个呀 ,于是我就在receiver里面new了一个

然后就报了如下的错


android.view.WindowManager$BadTokenException: Unable to add window – token null is not for an application
android.view.ViewRootImpl.setView(ViewRootImpl.java:567)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:269) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69) at android.app.Dialog.show(Dialog.java:323) at com.yipwey.dialogactivity.PushReceiver.onReceive(PushReceiver.java:16)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2508)
at android.app.ActivityThread.access$2000(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1323)


下面是我写的测试代码

public class PushReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Dialog dialog=new Dialog(context);
        dialog.setTitle("Dialog");
        dialog.show();
    }
}

在stackoverflow上找到了原因 http://stackoverflow.com/questions/19024940/android-error-unable-to-add-window-token-null-is-not-for-an-application

原因是因为传入的是Context,而需要的是Activity

查询SDK帮助文档:

Return the context of the single, global Application object of the current process. This generally should only be used if you need a Context whose lifecycle is separate from the current context, that is tied to the lifetime of the process rather than the current component.

在回来发现我这里是Receiver啊,并不是Activity
于是乎就要换一种方法了,也就是Dialog风格的Activity

这样既解决了这个问题,有可以再Activity里写控制的代码,下面我就抛砖引玉介绍一下吧

首先,要写一个style 并且集成 @android:style/Theme.Dialog

<style name="CustomTheme_Dialog" parent="@android:style/Theme.Dialog">
       <item name="android:windowBackground">@android:color/transparent</item>
       <item name="android:windowFrame">@null</item>
       <item name="android:windowActionBar">false</item>
       <item name="android:windowNoTitle">true</item>
       <item name="android:windowIsFloating">true</item>
       <item name="android:windowIsTranslucent">false</item>
       <item name="android:backgroundDimEnabled">true</item>
</style>

然后再你的Manifest中的Activity添加 android:theme="@style/CustomTheme_Dialog"

这样你的Activity就是dialog风格的了

public class DialogActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

下面是我的布局,

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.yipwey.dialogactivity.MainActivity">

    <Button
        android:id="@+id/btn"
        android:text="Hello World!"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

,然后我们运行一下

然后你会发现又报错了

Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
                                                                               at android.support.v7.app.AppCompatDelegateImplV7.createSubDecor(AppCompatDelegateImplV7.java:343)
                                                                               at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:312)
                                                                               at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:277)
                                                                               at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
                                                                               at com.yipwey.dialogactivity.MainActivity.onCreate(MainActivity.java:14)
                                                                               at android.app.Activity.performCreate(Activity.java:5308)
                                                                               at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1090)

原因是你继承了AppCompatActivity,改成Activity就可以了

然后就成功了

如果你想点击外部不消失的话 调用 setFinishOnTouchOutside(false);就可以了(注意:一定要在setContentView之前调用)

demo下载地址:http://download.csdn.net/detail/yewei02538/9602028