启动Activity时的方法调用(应用层)(MVC模式)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012585964/article/details/52343418

一,从桌面启动应用

从桌面启动一个应用其实质也是从一个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; i<N; i++) {
                    final 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启动的Activity
if (!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<Activity> {
...
     @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; i<N; i++) {
                    final 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.
 * <p>
 * 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。

猜你喜欢

转载自blog.csdn.net/u012585964/article/details/52343418
今日推荐