一,从桌面启动应用

从桌面启动一个应用其实质也是从一个Activity中启动另一个Activity,比如官方的实例代码中:
android/platform_packages_apps_launcher

    /**     * 点击桌面图标启动Intent指向的Activity     *     * @param v The view representing the clicked shortcut.     */    public void onClick(View v) {        Object tag = v.getTag();//获取点击位置        if (tag instanceof ApplicationInfo) {//是ApplicationInfo的一个成员            // Open shortcut            final Intent intent = ((ApplicationInfo) tag).intent;            startActivitySafely(intent);//启动应用        } else if (tag instanceof FolderInfo) {            handleFolderClick((FolderInfo) tag);        }    }    void startActivitySafely(Intent intent) {        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        try {            startActivity(intent);        } catch (ActivityNotFoundException e) {            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();        } catch (SecurityException e) {            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();            e(LOG_TAG, "Launcher does not have the permission to launch " + intent +                    ". Make sure to create a MAIN intent-filter for the corresponding activity " +                    "or use the exported attribute for this activity.", e);        }    }

二,Activity内启动Activity

因为现在几乎都是从AppCompatActivity创建Activity,所以我们从AppCompatActivity开始分析。AppCompatActivity的类继承关系如下:

我们知道,如果从自己的Activity中调用startActivity()方法,系统会在类族中从下到上依次查找,直到遇到一个startActivity()为止,所以为了方便观察,先找出各类中启动startActivity方法和startActivityForResult方法(如果类中有的话):
AppCompatActivity中没有,它会向上查找父类FragmentActivity。
FragmentActivity中有一个startActivityForResult(Intent intent, int requestCode),并且在此方法中又super了此方法,所以它会在执行完后继续向上查找startActivityForResult(intent, requestCode)方法并执行:

    /**     * Modifies the standard behavior to allow results to be delivered to fragments.     * This imposes a restriction that requestCode be <= 0xffff.     */    @Override    public void startActivityForResult(Intent intent, int requestCode) {        // If this was started from a Fragment we've already checked the upper 16 bits were not in        // use, and then repurposed them for the Fragment's index.        if (!mStartedActivityFromFragment) {            if (requestCode != -1) {                checkForValidRequestCode(requestCode);            }        }        super.startActivityForResult(intent, requestCode);    }

FragmentActivity的直接父类是BaseFragmentActivityJB,在它的类中有一个startActivityForResult(Intent intent, int requestCode,
@Nullable Bundle options)方法,显然不是FragmentActivity中那个方法调用的,FragmentActivity会再继续向上查找startActivityForResult(intent, requestCode),BaseFragmentActivityJB中的这个方法同样也super了startActivityForResult(intent, requestCode, options):

    @Override    public void startActivityForResult(Intent intent, int requestCode,            @Nullable Bundle options) {        // If this was started from a Fragment we've already checked the upper 16 bits were not in        // use, and then repurposed them for the Fragment's index.        if (!mStartedActivityFromFragment) {            if (requestCode != -1) {                checkForValidRequestCode(requestCode);            }        }        super.startActivityForResult(intent, requestCode, options);    }

然后中间几个类就没有启动Activity的方法了,看Activity:

    @Override    public void startActivity(Intent intent) {        this.startActivity(intent, null);    }
    @Override    public void startActivity(Intent intent, @Nullable Bundle options) {        if (options != null) {            startActivityForResult(intent, -1, options);        } else {            // Note we want to go through this call for compatibility with            // applications that may have overridden the method.            startActivityForResult(intent, -1);        }    }
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {        startActivityForResult(intent, requestCode, null);    }

因为View一般是填充到Activity中去的,如果在View类中封装的事件中需要启动Activity,会需要传入Context,这个Context一般都是所在Activity赋予,所以这种情况下也是Activity中启动Activity,所以下面判断了是不是从UI中启动:

     public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {        if (mParent == null) {//不是从UI中启动Activity            //实现应用检测代码的基类,内部类.ActivityResult表示返回的Activity执行的结果            Instrumentation.ActivityResult ar =                mInstrumentation.execStartActivity(//执行启动Activity                    this, mMainThread.getApplicationThread(), mToken, this,                    intent, requestCode, options);            if (ar != null) {                mMainThread.sendActivityResult(//主线程发送执行结果                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),                    ar.getResultData());            }            if (requestCode >= 0) {                // 如果这个开始请求一个结果, 我们可以禁止让这个activity 可见,直到收到返回结果。                // 设置这个代码使activity在 onCreate(Bundle savedInstanceState) 或者onResume() 期间处于隐藏状态,避免闪烁.                // 只有在要求返回结果时才这么做,这样保证我们可以获得返回的信息,当activity结束,不管会发生什么。                mStartedActivity = true;//表示启动Activity            }            cancelInputsAndStartExitTransition(options);            // TODO Consider clearing/flushing other event sources and events for child windows.        } else {            if (options != null) {                mParent.startActivityFromChild(this, intent, requestCode, options);            } else {                // Note we want to go through this method for compatibility with                // existing applications that may have overridden it.                mParent.startActivityFromChild(this, intent, requestCode);            }        }    }

在上面这个startActivityForResult中会判断是不是从界面中启动,不是则执行Instrumentation.execStartActivity,如果是则执行startActivityFromChild,Activity是UI:

public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,            int requestCode) {        startActivityFromChild(child, intent, requestCode, null);    }
public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,            int requestCode, @Nullable Bundle options) {        Instrumentation.ActivityResult ar =            mInstrumentation.execStartActivity(                this, mMainThread.getApplicationThread(), mToken, child,                intent, requestCode, options);        if (ar != null) {            mMainThread.sendActivityResult(                mToken, child.mEmbeddedID, requestCode,                ar.getResultCode(), ar.getResultData());        }        cancelInputsAndStartExitTransition(options);    }

startActivityFromChild中也是执行Instrumentation.execStartActivity,其有三个同名方法,一个执行的是来自Fragment,一个来自application的,还有一个是指定用户才可以调用的,这儿为第二个:

public ActivityResult execStartActivity(            Context who, IBinder contextThread, IBinder token, Activity target,            Intent intent, int requestCode, Bundle options) {        IApplicationThread whoThread = (IApplicationThread) contextThread;        Uri referrer = target != null ? target.onProvideReferrer() : null;        if (referrer != null) {            intent.putExtra(Intent.EXTRA_REFERRER, referrer);        }        if (mActivityMonitors != null) {//如果Activity监视器不为空            synchronized (mSync) {                final int N = mActivityMonitors.size();                for (int i=0; ifinal ActivityMonitor am = mActivityMonitors.get(i);                    if (am.match(who, null, intent)) {                        am.mHits++;                        if (am.isBlocking()) {//如果是阻塞的,暂停状态的                            return requestCode >= 0 ? am.getResult() : null;//如果有请求结果返回结果,如果没有返回null                        }                        break;                    }                }            }        }        try {            intent.migrateExtraStreamToClipData();            intent.prepareToLeaveProcess();            int result = ActivityManagerNative.getDefault()//与ActivityManagerService通信启动Activity                .startActivity(whoThread, who.getBasePackageName(), intent,                        intent.resolveTypeIfNeeded(who.getContentResolver()),                        token, target != null ? target.mEmbeddedID : null,                        requestCode, 0, null, options);            checkStartActivityResult(result, intent);        } catch (RemoteException e) {            throw new RuntimeException("Failure from system", e);        }        return null;    }

通过上面的方法可以得出,如果从我们继承自AppCompatActivit的Activity启动另一个Activity,程序执行的步骤:

结合代码可以看到从AppCompatActivity调用的startActivityForResult只是比从Activity中调用的多了以下这段代码:

//如果不是从Fragmengt启动的Activityif (!mStartedActivityFromFragment) {            if (requestCode != -1) {//如果请求码不是-1                checkForValidRequestCode(requestCode);//检查给定的请求码是否有效            }        }

来自BaseFragmentActivityEclair:

static void checkForValidRequestCode(int requestCode) {        if ((requestCode & 0xffff0000) != 0) {            throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");//请求码不能超过16位        }    }

三,Fragment中启动Activity

在Fragment中有启动Activity的方法,可以通过它启动Activity,但在android.app包和android.support.v4.app包两个包中都Fragment类,这时就得分情况了,使用哪个包中的就导入哪个包中的Fragment。

导入android.app.Fragment

调用android.app.Fragment中的startActivity或startActivityForResult:

    /**     * Call {@link Activity#startActivity(Intent)} from the fragment's     * containing Activity.     */    public void startActivity(Intent intent) {        startActivity(intent, null);    }    /**     * Call {@link Activity#startActivity(Intent, Bundle)} from the fragment's     * containing Activity.     */    public void startActivity(Intent intent, @Nullable Bundle options) {        if (mHost == null) {            throw new IllegalStateException("Fragment " + this + " not attached to Activity");        }        mHost.onStartActivityFromFragment(this /*fragment*/, intent, -1, options);    }
/**     * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's     * containing Activity.     */    public void startActivityForResult(Intent intent, int requestCode) {        startActivityForResult(intent, requestCode, null);    }    /**     * Call {@link Activity#startActivityForResult(Intent, int, Bundle)} from the fragment's     * containing Activity.     */    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {        if (mHost == null) {            throw new IllegalStateException("Fragment " + this + " not attached to Activity");        }        mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode, options);    }

可以看出startActivity和startActivityForResult调用的都是FragmentHostCallback.onStartActivityFromFragment,FragmentHostCallback是抽象类,Activity类中的内部类HostCallbacks是它的实现类:

class HostCallbacks extends FragmentHostCallback {...     @Override        public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode,                Bundle options) {            Activity.this.startActivityFromFragment(fragment, intent, requestCode, options);        }...}

Activity.startActivityFromFragment:

    public void startActivityFromFragment(@NonNull Fragment fragment,            @RequiresPermission Intent intent, int requestCode) {        startActivityFromFragment(fragment, intent, requestCode, null);    }    public void startActivityFromFragment(@NonNull Fragment fragment,            @RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {        startActivityForResult(fragment.mWho, intent, requestCode, options);    }

它又调用Activity类的隐藏方法startActivityForResult:

    /**     * @hide     */    @Override    public void startActivityForResult(            String who, Intent intent, int requestCode, @Nullable Bundle options) {        Uri referrer = onProvideReferrer();        if (referrer != null) {            intent.putExtra(Intent.EXTRA_REFERRER, referrer);        }        Instrumentation.ActivityResult ar =            mInstrumentation.execStartActivity(                this, mMainThread.getApplicationThread(), mToken, who,                intent, requestCode, options);        if (ar != null) {            mMainThread.sendActivityResult(                mToken, who, requestCode,                ar.getResultCode(), ar.getResultData());        }        cancelInputsAndStartExitTransition(options);    }

然后最终调用Instrumentation.execStartActivity,Fragment使用的这个方法和Activity使用的同名方法的第4个参数不同,虽然含义相同:

public ActivityResult execStartActivity(        Context who, IBinder contextThread, IBinder token, String target,        Intent intent, int requestCode, Bundle options) {        IApplicationThread whoThread = (IApplicationThread) contextThread;        if (mActivityMonitors != null) {            synchronized (mSync) {                final int N = mActivityMonitors.size();                for (int i=0; ifinal ActivityMonitor am = mActivityMonitors.get(i);                    if (am.match(who, null, intent)) {                        am.mHits++;                        if (am.isBlocking()) {                            return requestCode >= 0 ? am.getResult() : null;                        }                        break;                    }                }            }        }        try {            intent.migrateExtraStreamToClipData();            intent.prepareToLeaveProcess();            int result = ActivityManagerNative.getDefault()                .startActivity(whoThread, who.getBasePackageName(), intent,                        intent.resolveTypeIfNeeded(who.getContentResolver()),                        token, target, requestCode, 0, null, options);            checkStartActivityResult(result, intent);        } catch (RemoteException e) {            throw new RuntimeException("Failure from system", e);        }        return null;    }

流程可以简洁表示如下:

相关类图:

这儿使用了MVC架构,

;FragmentHostCallback类组为模型模块;Activity作为视图模块。

MVC架构模式

方便理解,特意百度图片:



模型(Model) “数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。(比较:观察者模式(软件设计模式))
这儿是把Fragment当作数据,FragmentHostCallback类组对Fragment进行业务处理的封装,其子类HostCallbacks是Activity的内部类,并对Activity中的一些方法进行调用(放在Activity中方便外部调用):

class HostCallbacks extends FragmentHostCallback<Activity> {    public HostCallbacks() {        super(Activity.this /*activity*/);    }    @Override    public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {        Activity.this.dump(prefix, fd, writer, args);    }    FragmentHostCallback(Activity activity) {        this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);    }    @Override    public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode,         Bundle options) {         Activity.this.startActivityFromFragment(fragment, intent, requestCode, options);    }...}

视图(View) 视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在它监视的数据模型那里注册。
Activity类此时在这儿充当视图层,如上在HostCallbacks的构造器中设置了模型关联的activity及上下文环境activity。Activity对控制器FragmentController进行引用,并进行一些方法调用:

final FragmentController mFragments = FragmentController.createController(new HostCallbacks());...mFragments.dispatchResume();mFragments.execPendingActions();

控制器(Controller) 控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变。
FragmentController和FragmentManager共同组成了控制器模块,FragmentController通过FragmentHostCallback.getFragmentManagerImpl()获得FragmentManager,然后共同对FragmentHostCallback进行控制,间接对Activity发挥作用:

/**意思是与FragmentManager一块为fragment宿主提供一个关键点,响应宿主管理fragment的生命周期。 * Provides integration points with a {@link FragmentManager} for a fragment host. * 

* It is the responsibility of the host to take care of the Fragment's lifecycle. * The methods provided by {@link FragmentController} are for that purpose. */public class FragmentController { private final FragmentHostCallback<?> mHost; /** * Returns a {@link FragmentController}. */ public static final FragmentController createController(FragmentHostCallback<?> callbacks) { return new FragmentController(callbacks); } private FragmentController(FragmentHostCallback<?> callbacks) { mHost = callbacks; }

MVC模式根据情景不同,可能会有好几个嵌套,一个类会充当好几个角色。现在应用中比较流行切某些场合下更好的是MVP模式,所以了解即可。

导入android.support.v4.app.Fragment

使用android.support.v4.app.Fragment会和使用android.app.Fragment之间有稍微的差异。
android.support.v4.app.Fragment启动Activity的方法和android.app.Fragment中的代码相同,这里略。
调用的都是FragmentHostCallback.onStartActivityFromFragment,这儿的FragmentHostCallback也是抽象类,但和那个不是一个类,虽然类名相同,但所在不是同一个包(这部分的Fragment相关类在android.support.v4.app包中),它的实现类是FragmentActivity类中的内部类HostCallbacks:

        @Override        public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {            FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode);        }        @Override        public void onStartActivityFromFragment(                Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) {            FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode, options);        }

都是调用FragmentActivity.startActivityFromFragment(参数不同):

    /**     * Called by Fragment.startActivityForResult() to implement its behavior.     */    public void startActivityFromFragment(Fragment fragment, Intent intent,            int requestCode) {        startActivityFromFragment(fragment, intent, requestCode, null);    }    /**     * Called by Fragment.startActivityForResult() to implement its behavior.     */    public void startActivityFromFragment(Fragment fragment, Intent intent,            int requestCode, @Nullable Bundle options) {        mStartedActivityFromFragment = true;        try {            if (requestCode == -1) {                ActivityCompat.startActivityForResult(this, intent, -1, options);                return;            }            checkForValidRequestCode(requestCode);            int requestIndex = allocateRequestIndex(fragment);            ActivityCompat.startActivityForResult(                    this, intent, ((requestIndex + 1) << 16) + (requestCode & 0xffff), options);        } finally {            mStartedActivityFromFragment = false;        }    }

ActivityCompat.startActivityForResult:

    public static void startActivityForResult(Activity activity, Intent intent, int requestCode,            @Nullable Bundle options) {        if (Build.VERSION.SDK_INT >= 16) {            ActivityCompatJB.startActivityForResult(activity, intent, requestCode, options);        } else {            activity.startActivityForResult(intent, requestCode);        }    }

如果版本大于等于16,调用ActivityCompatJB.startActivityForResult,否则调用宿主activity的startActivityForResult(intent, requestCode),ActivityCompatJB.startActivityForResult:

public static void startActivityForResult(Activity activity, Intent intent, int requestCode, Bundle options) {        activity.startActivityForResult(intent, requestCode, options);    }

宿主activity即是FragmentActivity或其子类,调用的是FragmentActivity.startActivityForResult。

 @Override    public void startActivityForResult(Intent intent, int requestCode) {        // If this was started from a Fragment we've already checked the upper 16 bits were not in        // use, and then repurposed them for the Fragment's index.        if (!mStartedActivityFromFragment) {            if (requestCode != -1) {                checkForValidRequestCode(requestCode);            }        }        super.startActivityForResult(intent, requestCode);    }    

后面略,请参考前面Activity中启动Activity.相关类关系和前面Fragment类关系相似,也不重复了。

附:app包中的fragment和v4包中的fragment的相关使用

1,app包中的fragment,因为这个是在3.0之后才有的,支持3.0以后的版本,如果需要支持更低版本,需要使用v4包中的fragment。’这两个类功能几乎一样,都是可以使用标签,区别是导入包时的包名是不一样的。对应的方法名类似,不尽相同,实现过程也有点差异,所以如果用混了会报错。

2,因为现在大部分都是基于AppCompatActivity使用Fragment,所以在Fragment中启动Activity如果要求返回结果,如果导入的是app包中的fragment,则有两种实现方案:

第一种:调用Fragment的startActivityForResult方法,然后在Fragment的onActivityResult的方法中处理返回的请求。

第二种:在Fragment中通过getActivity()方法获取到Fragment所在的FragmentActivity对象,调用activity对象的startActivityForResult方法启动Activity,然后在FragmentActivity的onActivityResult的方法中处理返回的请求。

四,其它组件中启动Activity

其他组件还可以启动Activity的有Service和Broadcast Receiver,他们都是脱Activity运行的。
在Service中可以直接调用startActivity(因为Service是Context的一个子类),Broadcast Receiver调用Context.startActivity,此时它们调用的方法实现都是ContextImpl.startActivity:

    @Override    public void startActivity(Intent intent) {        warnIfCallingFromSystemProcess();        startActivity(intent, null);    }    @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);    }

可以看到这儿有个判断intent中是否有个Intent.FLAG_ACTIVITY_NEW_TASK标志,如果没有就报错。在service中启动示例:

    Intent intent=new Intent(getApplicationContext(),AnotherActivity.class);    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);    startActivity(intent);

Broadcast Receiver同理。

五,最后附上一张图

注:这里都是用Intent传递信息,还可以使用PendingIntent。

更多相关文章

  1. Android(安卓)7.0 Launcher3的启动和加载流程分析----转载
  2. android ViewGroup删除子视图时应该注意的一个问题
  3. Android之Service组件
  4. Android(安卓)Parcel和Parcelable类
  5. 判断应用或Activity是否存在
  6. 【Android界面实现】Starting an Activity(Activity生命周期金字
  7. 第三部分 MediaPlayer的主要实现分析
  8. Android设置Dialog透明度、黑暗度方法
  9. RecyclerView 中 item 点击事件的优化

随机推荐

  1. Android(安卓)最近的一些新的功能
  2. Android(安卓)第五天 (下午)
  3. Android(安卓)Wifi几点
  4. 在ubuntu上编译android的mupdf
  5. Android(安卓)O 8.0 新功能预览
  6. Android(安卓)Spinner
  7. 【Android进阶】android:configChanges属
  8. Android(安卓)ScrollView 实现小说阅读界
  9. android 静音与振动
  10. Android四种Activity的加载模式