Android对话框之Context

代码就这么一段:
new AlertDialog.Builder(getApplicationContext(),R.style.MyAlertDialogStyle)

        .setTitle("温柔")

        .setMessage("不知道 不明了 不想要\n" +

                "为什么 我的心")

        .setPositiveButton("确定",null)

        .setNegativeButton("取消",null)

        .show();

 

这个时候报错了: Unable to add window -- token null is not for an application

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
at android.view.ViewRootImpl.setView(ViewRootImpl.java:576)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:269)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
at android.app.Dialog.show(Dialog.java:289)
at android.app.AlertDialog$Builder.show(AlertDialog.java:951)
at cn.bvin.app.androidtest_asgit.MainActivity$1.onClick(MainActivity.java:24)
at android.view.View.performClick(View.java:4446)
at android.view.View$PerformClick.run(View.java:18480)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5294)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:680)
at dalvik.system.NativeStart.main(Native Method)

 

为什么会这样呢,看一下源码:

 /**

     * Create a Dialog window that uses the default dialog frame style.

     * 

     * @param context The Context the Dialog is to run it.  In particular, it

     *                uses the window manager and theme in this context to

     *                present its UI.

     */

    public Dialog(Context context) {

        this(context, 0, true);

    }



    /**

     * Create a Dialog window that uses a custom dialog style.

     * 

     * @param context The Context in which the Dialog should run. In particular, it

     *                uses the window manager and theme from this context to

     *                present its UI.

     * @param theme A style resource describing the theme to use for the 

     * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style 

     * and Theme Resources</a> for more information about defining and using 

     * styles.  This theme is applied on top of the current theme in 

     * <var>context</var>.  If 0, the default dialog theme will be used.

     */

    public Dialog(Context context, int theme) {

        this(context, theme, true);

    }



    Dialog(Context context, int theme, boolean createContextThemeWrapper) {

        if (createContextThemeWrapper) {

            if (theme == 0) {

                TypedValue outValue = new TypedValue();

                context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,

                        outValue, true);

                theme = outValue.resourceId;

            }

            mContext = new ContextThemeWrapper(context, theme);

        } else {

            mContext = context;

        }



        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

        Window w = PolicyManager.makeNewWindow(mContext);

        mWindow = w;

        w.setCallback(this);

        w.setOnWindowDismissedCallback(this);

        w.setWindowManager(mWindowManager, null, null);

        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);

    }

看到上面public的构造方法都是重载下面那个缺省构造方法,三个形参,但是我们看到public的构造方法里最后的createContextThemeWrapper参数都为true

Context context, int theme, boolean createContextThemeWrapper
所以这时mContext的是创建了一个ContextThemeWrapper对象,这下就明白了。

Service,Application,Broadcast都是继承ContextWraper,只有Activity是继承ContextThemeWrapper。
而ContextThemeWrapper又是继承ContextWraper,ContextWraper继承Context。

所以传Activity.this拿到的Context是可以创建ContextThemeWrapper对象的。
再看一下ContextThemeWrapper的源码:
    public ContextThemeWrapper() {

        super(null);

    }

    

    public ContextThemeWrapper(Context base, int themeres) {

        super(base);

        mThemeResource = themeres;

    }



    @Override protected void attachBaseContext(Context newBase) {

        super.attachBaseContext(newBase);

    }



    ...



    @

    Override public void setTheme(int resid) {

        mThemeResource = resid;

        initializeTheme();

    }
ContextThemeWrapper有两个构造函数,一个是不带参的,一个是带一个Context和themeRes的,上面dialog的构造方法中是通过后者来创建的Context。
当然用无构造方法也可以创建ContextThemeWrapper对象,就如上图,attachBaseContext方法可以把Context传递进去,
setTheme则可以把themeRes设置进去。。。

最前沿Android技术分享尽在Android技术分享社,拿起你们的手机打开微信扫一扫,关注我的公众号就给你推荐优秀的知识文章或技术分享了!

Android对话框之Context



你可能感兴趣的:(android)