zoukankan      html  css  js  c++  java
  • Application中以标准模式启动Activity报错的原因分析

    个人博客

    http://www.milovetingting.cn

    Application中以标准模式启动Activity报错的原因分析

    Android中,启动的Activity都会运行在相应的任务栈中。如果直接在Application中以标准模式启动Activity,则会报出以下错误(Android7、Android8除外,后面会分析):

    Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
    at android.app.ContextImpl.startActivity(ContextImpl.java:912)
    at android.app.ContextImpl.startActivity(ContextImpl.java:888)
    at android.content.ContextWrapper.startActivity(ContextWrapper.java:379)
    

    错误信息提示需要FLAG_ACTIVITY_NEW_TASK的Flag.

    在Activity中调用getApplication()或者getApplicationContext(),最终获取到的都是Application,那么getApplication().startActivity()或者getApplicationContext().startActivity()方法都在Application中

    @Override
        public void startActivity(Intent intent) {
            mBase.startActivity(intent);
        }
    

    在Application的startActivity方法里,又通过mBase来调用startActivity,而mBase就是ContextImpl。ContextImpl的startActivity方法

    @Override
        public void startActivity(Intent intent) {
            warnIfCallingFromSystemProcess();
            startActivity(intent, null);
        }
    

    这个方法里调用了另一个重载方法

    //Android6
    @Override
        public void startActivity(Intent intent, Bundle options) {
            warnIfCallingFromSystemProcess();
            if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                throw new AndroidRuntimeException(
                        "Calling startActivity() from outside of an Activity "
                        + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                        + " Is this really what you want?");
            }
            mMainThread.getInstrumentation().execStartActivity(
                    getOuterContext(), mMainThread.getApplicationThread(), null,
                    (Activity) null, intent, -1, options);
        }
    

    Android6中,在这个方法里,看到了前面抛出的异常提示。在这里判断了,如果没有加FLAG_ACTIVITY_NEW_TASK的Flag,就会抛出异常。

    再来看Android7中的方法

    @Override
        public void startActivity(Intent intent, Bundle options) {
            warnIfCallingFromSystemProcess();
    
            // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
            // generally not allowed, except if the caller specifies the task id the activity should
            // be launched in.
            if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                    && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
                throw new AndroidRuntimeException(
                        "Calling startActivity() from outside of an Activity "
                        + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                        + " Is this really what you want?");
            }
            mMainThread.getInstrumentation().execStartActivity(
                    getOuterContext(), mMainThread.getApplicationThread(), null,
                    (Activity) null, intent, -1, options);
        }
    

    可以看到,在Android7中,相对Android6,抛出异常还需要符合其它的几个条件。而从前面Application的startActivity方法来看,Bundle类型的options参数为null,所以这个条件不成立,不会抛出异常。

    再来看Android8中的方法

     @Override
        public void startActivity(Intent intent, Bundle options) {
            warnIfCallingFromSystemProcess();
    
            // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
            // generally not allowed, except if the caller specifies the task id the activity should
            // be launched in.
            if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                    && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
                throw new AndroidRuntimeException(
                        "Calling startActivity() from outside of an Activity "
                        + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                        + " Is this really what you want?");
            }
            mMainThread.getInstrumentation().execStartActivity(
                    getOuterContext(), mMainThread.getApplicationThread(), null,
                    (Activity) null, intent, -1, options);
        }
    

    和Android7一样,也判断了options,由于options为null,因此条件不成立,也不会抛出异常。

    再来看下Android9中的方法

    @Override
        public void startActivity(Intent intent, Bundle options) {
            warnIfCallingFromSystemProcess();
    
            // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
            // generally not allowed, except if the caller specifies the task id the activity should
            // be launched in. A bug was existed between N and O-MR1 which allowed this to work. We
            // maintain this for backwards compatibility.
            final int targetSdkVersion = getApplicationInfo().targetSdkVersion;
    
            if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                    && (targetSdkVersion < Build.VERSION_CODES.N
                            || targetSdkVersion >= Build.VERSION_CODES.P)
                    && (options == null
                            || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
                throw new AndroidRuntimeException(
                        "Calling startActivity() from outside of an Activity "
                                + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                                + " Is this really what you want?");
            }
            mMainThread.getInstrumentation().execStartActivity(
                    getOuterContext(), mMainThread.getApplicationThread(), null,
                    (Activity) null, intent, -1, options);
        }
    

    在Android9中,对于options==null用了||判断,那么ActivityOptions.fromBundle(options).getLaunchTaskId() == -1,条件还是会成立,还是会抛出异常。

    可以看到,在Android7和Android8中,可以在Application中直接启动Activity,而不需要增加FLAG_ACTIVITY_NEW_TASK的Flag。

  • 相关阅读:
    Lua手册中的string.len 不解
    计算机词汇(Computer Glossary)
    Qt 信号和槽机制的优缺点
    多线程,什么时候该使用?
    Linux进行挂起和杀死挂起进程
    struct和class的区别
    Number of 1 Bits
    Pascal's Triangle
    Excel Sheet Column Title
    c++单向链表
  • 原文地址:https://www.cnblogs.com/milovetingting/p/12465261.html
Copyright © 2011-2022 走看看