All of my articles are collected in this article, and will be updated in time: Knowledge is long, the road of the walker will end in no words (My Programming Road)


Zero, preface,

1. Knowledge points of this article
[1]. Introduction to Intents and [implicit call] and [display call] [2]. Serialization and deserialization of objects: [Parcelable] and 'Serializable] [3].[Bundle] and its data transfer in intents [4]Copy the code

2. Intent overview

Class name :Intent Parent class :Object Interface :[Parcelable, Cloneable] Package name: Android.contentNumber of dependent classes :52 Number of internal classes/interfaces :3 Number of source lines: 10086 Number of source lines (except comments):3407 Number of properties: 24 Number of methods :164Copy the code

The Intent class is simple to understand

I’ve seen this class since my first day on Android: Intents are large, but they look like 10086 lines. They are large except for comments and blank lines. They are bare code 3407. Starting from scratch, he is a loyal partner of Android’s four components, jumping activities, sending BroadcastReceivers, and starting services. Components communicate with each other through intents and transmit data.


1.Intent constructor

There are eight constructors in the source code. The two above are null and hidden. The two on the left are copied to generate Intent objects. The copies of the two parameters are similar. The two on the right are used to generate the Intent object by setting the matching information (implicit). The two below are used to generate the Intent object (explicit).


2. Common member variables in intents

Component: destination component(application package name + component class name) Action: action of intent Action category: category of action Data: represents the data to be manipulated with the actiontype(data type) : Description of the data example extras: (extended information) : (extended information) Flags: expected mode of operation for this intentCopy the code

Implicit use of Intents

That do not specify a component name, through the action, the category, the data, the information such as the type open the component system built in many applications, we can use this information to match open the need of application


1. Only Action is matched
1.1: Create an Activity:ActivityJustAction

List is very simple, for the Activity sets intent – filter custom action:www.toly1994.com.ActivityJustAction this name literally, As long as you use the corresponding category (usually unique), of course, it can not be unique, there is no category will break, so I’ll give it a default category, which is the category of action

class ActivityJustAction : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(LinearLayout(this))
        title = "ActivityJustAction"}} - > [AndroidManifest. XML configuration] -- -- -- -- -- -- -- -- -- -- -- -- < the activity of the android: name =".activity.ActivityJustAction">
    <intent-filter>
        <action android:name="www.toly1994.com.ActivityJustAction"></action>
        <category android:name="android.intent.category.DEFAULT"></category>
    </intent-filter>
</activity>
Copy the code

1.2: Intent opens the specified Action:

It’s like a person saying, I’m looking for prosperity, and prosperity comes

---->[IntentActivity]--------------
id_btn_just_action.setOnClickListener { v ->
    val intent = Intent("www.toly1994.com.ActivityJustAction")
    startActivity(intent)
}
Copy the code

1.3: BothProsperous wealthHow to do?

Create an ActivityJustAction2, intent-filter with the same intent. Since both are called “Rich”, bring them in and let you choose one (you should encounter them often).

class ActivityJustAction2 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(LinearLayout(this))
        title = "ActivityJustAction2"
    }
}

<activity android:name=".activity.ActivityJustAction2">
    <intent-filter>
        <action android:name="www.toly1994.com.ActivityJustAction2"></action>
        <category android:name="android.intent.category.DEFAULT"></category>
    </intent-filter>
</activity>
Copy the code

2. Matchaction+category

An intent-filter can be divided into multiple categories, just like an object can be divided into multiple domains. For example, people, programmers and Chinese citizens can refer to the same person. After adding category, you can say “I want to find a programmer named Wang CAI”

-- -- -- - > [AndroidManifest. XML configuration] -- -- -- -- -- -- -- -- -- -- -- -- < activity android: name =".activity.ActivityJustAction">
    <intent-filter>
        <action android:name="www.toly1994.com.ActivityJustAction"></action>
        <category android:name="android.intent.category.DEFAULT"></category>
        <category android:name="www.toly1994.com.people"></category>
        <category android:name="www.toly1994.com.coder"></category>
    </intent-filter>
</activity>

<activity android:name=".activity.ActivityJustAction2">
    <intent-filter>
        <action android:name="www.toly1994.com.ActivityJustAction"></action>
        <category android:name="android.intent.category.DEFAULT"></category>
        <category android:name="www.toly1994.com.dog"></category>
        <category android:name="www.toly1994.com.erha"></category>
    </intent-filter>
</activity>

---->[IntentActivity]--------------
id_btn_just_action.setOnClickListener { v ->
    val intent = Intent("www.toly1994.com.ActivityJustAction")
    //intent.addCategory("www.toly1994.com.coder"/ / 1 / / intent. AddCategory ("www.toly1994.com.people"/ / 1 / / intent. AddCategory ("www.toly1994.com.dog") / / 2 intent. AddCategory ("www.toly1994.com.erha"// Start 2 startActivity(intent)}Copy the code

3. Behavior + Add resource location identifier:action + data


://
?

3.1: Opens a web page

id_btn_open_web.setOnClickListener { v ->
    val intent = Intent(Intent.ACTION_VIEW)
    intent.data = Uri.parse("https://juejin.cn/user/149189281194766")
    startActivity(intent)
}
Copy the code

3.2: Opens an SMS message

/ / Private fun sendMsg(number: String, body: String) { val intent = Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:$number"))
    intent.putExtra("sms_body", body)
    startActivity(intent)
}
Copy the code

4. Launch the Image Library Activity with Intent (action+type)

Type an application according to the action, append the MIME type

/** * Open gallery */ private funopenGallery() {
    val intent = Intent(Intent.ACTION_PICK)
    intent.type = "image/*";
    startActivity(intent)
}
Copy the code

Take a look at how the source of the gallery is configured


5.Intent opens the fileaction+type+data

5.1: adaptation

Android API 24 and above have restrictions on file URIs that need to be adapted

/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2018/10/300030 :18:38<br/> * Email: [email protected]<br/> * Description: Public class Compat {public static void fileUri(Context Context, Intent Intent, File File, Stringtype) {// Determine if it is AndroidN or higherif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", file);
            intent.setDataAndType(contentUri, type);
        } else {
            intent.setDataAndType(Uri.fromFile(file), type); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); }}} - > [AndroidManifest. XML configuration provider] -- -- -- -- -- - <! --android:authorities="This application package name. fileProvider"-->
<provider android:name="android.support.v4.content.FileProvider"
          android:authorities="com.toly1994.tolyservice.fileProvider"
          android:grantUriPermissions="true"
          android:exported="false">
    <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/> </provider> ---->[xml/file_paths.xml]----------- <? xml version="1.0" encoding="utf-8"? > <paths> <! --Android/data/ name of this application package /--> <external-path path="Android/data/com.toly1994.tolyservice/" name="files_root" />
    <external-path path="." name="external_storage_root" />
</paths>
Copy the code

5.2:

Id_btn_music.setonclicklistener {v ->// audio val intent = Intent(intent.action_view) val file = file ("/sdcard/ Toly/Courage - Jingru Leong -1772728608-1.mp3")
    Compat.fileUri(this, intent, file, "audio/mp3"} id_bTN_video.setonClickListener {v ->// video val intent = Intent(Intent.action_view) val file = File("/sdcard/toly/cy3d.mp4")
    Compat.fileUri(this, intent, file, "video/mp4"} id_btn_txt.setonClickListener {v ->// text val intent = Intent(Intent.action_view) val file = File("/ sdcard/toly/dragon. TXT")
    Compat.fileUri(this, intent, file, "text/*"} id_bTN_pic.setonClickListener {v ->// Image val intent = Intent(Intent.action_view) val file = File("/sdcard/toly/touch.jpg.png")
    Compat.fileUri(this, intent, file, "image/*")
    startActivity(intent)
}
Copy the code

In the library source code for opening an image configuration: implicit Intent to grab action, category, data, type four points


Intents are explicitly called

The components that need to be enabled have been specified

1. Open the componentThis component context + target component bytecode

This is our most commonly used, open the Activity, Service, BroadcastReceiver

private fun openComponent() {
    val intent = Intent(this, MainActivity::class.java)
    startActivity(intent)
}
Copy the code


2. com ponentName introduction

Start an Activity with an Intent

---->[Intent#Intent(Context, Class
      )] -- -- -- -- -- -- --public Intent(Context packageContext, Class<? > cls) { mComponent = new ComponentName(packageContext, cls); } The core method is ComponentName, as the name implies"Component Name"The first line of the source code says: an identifier for a specific application component ---->[ComponentName#ComponentName(Context, lang.Class
      )] -- -- -- -- -- -- -- --public ComponentName(@NonNull Context pkg, @NonNull Class<? > cls) { mPackage = pkg.getPackageName(); mClass = cls.getName(); } -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the ComponentName is a relatively simple class, the core is two mPackage and mClass member variables In this two-parameter construct, mPackage is the package name of the context passed in, and mClass is the class name of the target componentCopy the code

Take a look at the ComponentName construction of two strings, which can express their role and also realize the function of opening the component, so know the package name of the project, and the full class name of the component, you can open the component

val intent = Intent()
val compName = ComponentName(
    "com.toly1994.tolyservice",// The package name of the project"com.toly1994.tolyservice.activity.MainActivity"Intent.ponent = compName startActivity(Intent) intent.ponent = compName startActivity(Intent)Copy the code

3. Open wechat:Package name + target component class name + Flag
private fun openComponent() {
    val intent = Intent()
    intent.flags=Intent.FLAG_ACTIVITY_NEW_TASK
    val compName = ComponentName(
        "com.tencent.mm",// The package name of this component"com.tencent.mm.ui.LauncherUI"Intent.ponent = compName startActivity(Intent)} intent.ponent = compName startActivity(Intent)}Copy the code

4. Copy the structure source
-- -- -- - > [Intent copy construction] -- -- -- -- -- -- -- -- - public Intent Intent o {this (o, COPY_MODE_ALL); } / / | - the use of two reference [COPY_MODE_ALL] model -- -- -- - > [Intent two to copy] -- -- -- -- -- -- -- -- -- private Intent (Intent o, @CopyMode int copyMode) { this.mAction = o.mAction; this.mData = o.mData; this.mType = o.mType; this.mPackage = o.mPackage; this.mComponent = o.mComponent;if(o.mCategories ! = null) { this.mCategories = new ArraySet<>(o.mCategories); } / / | -- at this point to the category, the action, data,type, component, package field copy / / | - COPY_MODE_ALL, as the name implies, put all the content of the copyif(copyMode ! = COPY_MODE_FILTER) { this.mFlags = o.mFlags; this.mContentUserHint = o.mContentUserHint; this.mLaunchToken = o.mLaunchToken;if(o.mSourceBounds ! = null) { this.mSourceBounds = new Rect(o.mSourceBounds); }if(o.mSelector ! = null) { this.mSelector = new Intent(o.mSelector); }if(copyMode ! = COPY_MODE_HISTORY) {if(o.mExtras ! = null) { this.mExtras = new Bundle(o.mExtras); }if (o.mClipData != null) {
                this.mClipData = new ClipData(o.mClipData);
            }
        } else {
            if(o.mExtras ! = null && ! o.mExtras.maybeIsEmpty()) { this.mExtras = Bundle.STRIPPED; } // Alsoset "stripped" clip data when we ever log mClipData inThe (broadcast) // history.}}} ----cloneMethod]------------------ @override public Objectclone() {
    returnnew Intent(this); } | - according to the intent object calls, returns a new instance directly, essentially copying structure, there is no differenceCopy the code

4. Serialization and deserialization

What does serialization do?

1. Store object data permanently (in a file or on disk) and deserialize to generate object 2 as needed. 3. Pass the serialized object when an Intent is usedCopy the code

1. Serialization of objectsSerializable

Class Person(var name: String? , var age: Int) : Serializable { override fun toString(): String {return "Person{" +
                "name='" + name + '\''.toString() + ", age=" + age + '}'.toString() } }Copy the code

2.1:SerializableSerialization is saved to disk

val toly = Person("toly", 24)
val file = File(cacheDir, "toly.obj")
val oos = ObjectOutputStream(FileOutputStream(file))
oos.writeObject(toly)
oos.close()
Copy the code

2.2: Deserialization of instantiated objects from disk

val ois = ObjectInputStream(FileInputStream(file))
val toly = ois.readObject() as Person
ois.close()
Copy the code

2.3: Limits the serialization mode of fields

Use the @Transient(kotlin) or Transient(Java) keyword when some fields don’t need to be serialized. For example, I don’t want the name field to be serialized. (Because the more fields, the more resources consumed)

class Person(@Transient var name: String? , var age: Int) : Serializable { override fun toString(): String {return "Person{" +
                "name='" + name + '\''.toString() + ", age=" + age + '}'.toString() } }Copy the code

2.4:serialVersionUID

If you look at the Android source code, all classes that implement Serializable have a constant 'serialVersionUID'. When deserializing, the JVM compares the incoming byte stream to the serialVersionUID in the current class, deserializes if it is consistent, or throws an InvalidCastException if the serialized version is not consistent.Copy the code

3.ParcelableImplement object serialization (Java version)

When a Parcelable interface must implement describeContents and writeToParcel methods feel awkward, but AndroidStudio has a quick way to generate

/** * Author: Zhang Feng Jiete Lie <br/> * Time: 2019/1/21/021:22:30<br/> * Email: [email protected]<br/> * Description: */ public class Book implements Parcelable {private String name; private int price; public Book(String name, int price) { this.name = name; this.price = price; } @Override public intdescribeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
        dest.writeInt(this.price);
    }

    protected Book(Parcel in) {
        this.name = in.readString();
        this.price = in.readInt();
    }

    public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel source) {
            return new Book(source);
        }

        @Override
        public Book[] newArray(int size) {
            returnnew Book[size]; }}; @Override public StringtoString() {
        return "Book{" +
                "name='" + name + '\'' + ", price=" + price + '}'; }}Copy the code
3.ParcelablewithSerializableThe comparison of

This little reference article, well said

Package. Parcelable belongs to package the android OS Serializable belong to Java. IO | - package which illustrates the Parcelable can only be used in the android P Ibinder as information carrier, On the memory overhead is small, P in terms of performance than S S when serialized operation will produce a large number of temporary variables, (reflection) leading to GC frequently called | - Parcelable performance superior to the Serializable Parcelable reads and writes data directly from memory while Serializable reads and writes data to disk using IO streams. Serializable (Parcelable may not be available in different Android versions)Copy the code

Data delivery for Intents

In addition to a whole bunch of sets of attributes, an Intent has a whole bunch of putExtra to hold data. An Intent can not only pass “commands”, but also carry data. There are all sorts of ways to put data


1. Transfer common data types

Since there are many common types, I will choose three to represent them. The others are similar. How to put them

----> -------- val intent = Intent(this, ToActivity::class.java) //String data intent.putextra ()"stringData"."Zhang Feng Jie Te Li"Intent.putextra (intent.putextra) intent.putextra (intent.putextra)"intData"Val arr = Intent.putextra (arrayListOf(1, 2, 3, 4, 5) Intent.putextra (arrayListOf(1, 2, 3, 4, 5) Intent.putextra (intent.putextra)"arrData", arr)
startActivity(intent)

---->[ToActivity#onCreate]--------
var result = ""
val stringData = intent.getStringExtra("stringData")
val intData = intent.getIntExtra("intData", 10)
val arrData = intent.getIntegerArrayListExtra("arrData")
result+=intData.toString()+"\n"
if(stringData ! = null) { result+=stringData+"\n"
}
if(arrData ! = null) { result+=arrData.toString()+"\n"
}
id_tv_result.append(result)
Copy the code

2. The Intent passes the Bundle

It’s just key-value pairs, there’s nothing magical about it. There is also a bunch of put, the most important of which is the Parcelable/Serializable method that has put objects

A mapping from String keys to various {@link Parcelable} values. String key mapping to different values (link to Parcelable)Copy the code

-- -- -- - > [FromActivity clicked] -- -- -- -- -- -- -- -- val intent = intent (this, ToActivity::class.java) val bundle = bundle () val toly = Person()"toly", 24)
bundle.putSerializable("person"Val book = book (, toly)"The Fantasy.", 10000)
bundle.putParcelable("book", book)
intent.putExtra("bean", bundle)
startActivity(intent)

---->[ToActivity#onCreate]--------
val bundle = intent.getBundleExtra("bean")
if(bundle ! = null) { val personBean = bundle.get("person") as Person
    val bookBean = bundle.get("book") as Book
}
Copy the code


Six: Android source codeintent-filterAnalysis process of

1. Analyze the process

After being started, PackageManagerService scans system and third-party app information and instantiates PackageParser object PP in scanPackageLI. PackageParser's parseBaseApk parses Androidmanifest.xml and returns a Package object to parse androidmanifest.xml for all apps in the phone. Build a tree of all the apps in the phone from this treeCopy the code
---->[PackageParser#parseMonolithicPackage]------------@deprecated public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {// Deprecated... final AssetManager assets = new AssetManager(); try { final Package pkg = parseBaseApk(apkFile, assets, flags); pkg.codePath = apkFile.getAbsolutePath();return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }

private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";

---->[PackageParser# parseBaseApk 3 refs] -- -- -- -- -- -- -- -- -- -- -- --private Package parseBaseApk(File apkFile, AssetManager assets, int flags) throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); / / a little... Resources res = null; XmlResourceParser parser = null; // Build an Xml parser try {res = new Resources(assets, mMetrics, null); assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); Final String[] outError = new String[1]; // Open 'AndroidManifest. final Package pkg = parseBaseApk(res, parser, flags, outError);if (pkg == null) {
            throw new PackageParserException(mParseError,
                    apkPath + " (at " + parser.getPositionDescription() + ")." + outError[0]);
        }

        pkg.volumeUuid = volumeUuid;
        pkg.applicationInfo.volumeUuid = volumeUuid;
        pkg.baseCodePath = apkPath;
        pkg.mSignatures = null;
        returnpkg; / / a little... } ---->[PackageParser# parseBaseApk 4 refs] -- -- -- -- -- -- -- -- -- -- -- --| -- -- -- -- -- -- -- -- the core of all of the logic to parse the XML in this method, very long, -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- here from the application of parsing begins to see -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- private Package parseBaseApk (Resources res, XmlResourceParser Parser, int Flags, String[] outError) throws XmlPullParserException, IOException {// Omit... String tagName = parser.getName();if (tagName.equals("application") {// Start parsing application // // The parseBaseApplication method is called, where the activity is parsedif(! parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {return null;
            }
            
---->[PackageParser#parseBaseApplication]------------private boolean parseBaseApplication(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)while ((type= parser.next()) ! = XmlPullParser.END_DOCUMENT && (type! = XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }

        String tagName = parser.getName();
        if (tagName.equals("activity"Activity a = parseActivity(owner, res, Parser, attrs, flags, outError,false,
                    owner.baseHardwareAccelerated);
            if (a == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }
            owner.activities.add(a);
        } else if (tagName.equals("receiver") {// Receiver Activity a = parseActivity(owner, res, Parser, attrs, flags, outError,true.false);
            if (a == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }
            owner.receivers.add(a);

        } else if (tagName.equals("service"Service s = parseService(owner, res, Parser, attrs, flags, outError);if (s == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }

            owner.services.add(s);

        } else if (tagName.equals("provider"Provider p = parseProvider(owner, res, Parser, attrs, flags, outError);if (p == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false; } owner.providers.add(p); / / a little... There's a lot of parsing going onreturn true;
}

---->[PackageParser#parseActivity]------------private Activity parseActivity(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, boolean receiver, boolean hardwareAccelerated) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestActivity); / / a little... // Start parsing the intent-filterif (parser.getName().equals("intent-filter") {// Create ActivityIntentInfo ActivityIntentInfo intent = new ActivityIntentInfo(a); // Call the parseIntent methodif(! parseIntent(res, parser, attrs,true.true, intent, outError)) {
                return null;
            }
            if (intent.countActions() == 0) {
            } else{ a.intents.add(intent); / / a little...return a;
}

---->[PackageParser#parseIntent]------------private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs, boolean allowGlobs, boolean allowAutoVerify, IntentInfo outInfo, String[] outError) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestIntentFilter); / / a little... int outerDepth = parser.getDepth(); inttype;
    while ((type= parser.next()) ! = XmlPullParser.END_DOCUMENT && (type! = XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }
        String nodeName = parser.getName();
        if (nodeName.equals("action") {// Parse the action String value = attrs.getAttributeValue(ANDROID_RESOURCES,"name");
            if (value == null || value == "") {
                outError[0] = "No value supplied for <android:name>";
                return false;
            }
            XmlUtils.skipCurrentTag(parser);

            outInfo.addAction(value);
        } else if (nodeName.equals("category") {// parse category String value = attrs.getAttributeValue(ANDROID_RESOURCES,"name");
            if (value == null || value == "") {
                outError[0] = "No value supplied for <android:name>";
                return false;
            }
            XmlUtils.skipCurrentTag(parser);
            outInfo.addCategory(value);
        } else if (nodeName.equals("data"Analytical data)) {/ / sa = res. ObtainAttributes (attrs. Com. Android. Internal. R.s. Tyleable AndroidManifestData); String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);if(str ! = null) { try { outInfo.addDataType(str); } catch (IntentFilter.MalformedMimeTypeException e) { outError[0] = e.toString(); sa.recycle();return false; }}return true;
}

Copy the code
2.startActivity(intent)What did you do?

After a series of calls to startActivity, the final core is the following method, the Instrumentation class that was covered in the previous article, which is really the servant of the Activity

------>[Activity#startActivityForResult]----------------------
   public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if(mParent == null) { options = transferSpringboardActivityOptions(options); Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); / / a little... } } ------>[Instrumentation#execStartActivity]----------------------
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(who);
            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;
    }

------>[ActivityManagerNative#getDefault]----------------------
static public IActivityManager getDefault() {
    return gDefault.get();
}

------>[ActivityManagerNative#Singleton]----------------------
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager"."default service binder = "+ b); } IActivityManager am = asInterface(b); / / IActivityManager creationif (false) {
            Log.v("ActivityManager"."default service = " + am);
        }
        returnam; }}; ------>[ActivityManagerNative#asInterface]----------------------| -- -- -- -- -- -- -- -- here you can see the get IActivityManager object is a ActivityManagerProxy object static public IActivityManager asInterface (IBinder obj) {if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in! = null) {return in;
        }
        returnnew ActivityManagerProxy(obj); } > Now focus on ActivityManagerProxyCopy the code

Who is ActivityManagerProxy?

Let’s start with IActivityManager, which is an interface that defines a number of Activity management methods as its implementation class, the ActivityManagerProxy, which implements these methods


---->[ActivityStackSupervisor#startActivity]--------
 @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
        
---->[ActivityStackSupervisor#startActivityAsUser]--------
 @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);

---->[ActivityStackSupervisor#resolveActivity]--------ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags, ProfilerInfo profilerInfo, int userId) { // Collect information about the target of the Intent. ActivityInfo aInfo; Try {ResolveInfo rInfo = // getPackageManager is obtained from AppGlobals. Is a package manager AppGlobals. GetPackageManager (). ResolveIntent (intent, resolvedType, PackageManager.MATCH_DEFAULT_ONLY | ActivityManagerService.STOCK_PM_FLAGS, userId); aInfo = rInfo ! = null ? rInfo.activityInfo : null; ---->[ActivityStackSupervisor#resolveActivity]--------
public static IPackageManager getPackageManager{// Obtain the PackageManager from ActivityThreadreturn ActivityThread.getPackageManager();
}

---->[ActivityThread#getPackageManager]--------
public static IPackageManager getPackageManager() {
    if(sPackageManager ! = null) { //Slog.v("PackageManager"."returning cur default = " + sPackageManager);
        returnsPackageManager; } / / by ServiceManager package manager for IBinder IBinder b = ServiceManager. GetService ("package");
    //Slog.v("PackageManager"."default service binder = "+ b); / / object generated IPackageManager sPackageManager = IPackageManager Stub. AsInterface (b); //Slog.v("PackageManager"."default service = " + sPackageManager);
    returnsPackageManager; } // The next focus is on PackageManager and IPackageManagerCopy the code
IPackageManager.aidlThe method is in the description of

The PackageManagerService must also implement the queryIntentActivities method as the ipackAgemanager. Stub implementation class. It checks to see if the intent matches the aiDL

---->[PackageManagerService#queryIntentActivities]------------@Override public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, Int userId) {// Omit... Synchronized (mPackages) {final String pkgName = Intent.getPackage (); synchronized (mPackages) {final String pkgName = Intent.ifPkgName == null) {// omit... //ActivityIntentResolver#queryIntent Performs the queryList<ResolveInfo> result = mActivities.queryIntent( intent, resolvedType, flags, userId); / / a little... }return result;
        }
        final PackageParser.Package pkg = mPackages.get(pkgName);
        if(pkg ! = null) {return filterIfNotPrimaryUser(
                    mActivities.queryIntentForPackage(
                            intent, resolvedType, flags, pkg.activities, userId),
                    userId);
        }
        return new ArrayList<ResolveInfo>();
    }
}

---->[PackageManagerService$ActivityIntentResolver#queryIntent]------------
final class ActivityIntentResolver
        extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
    public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
            boolean defaultOnly, int userId) {
        if(! sUserManager.exists(userId))returnnull; mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; // The parent class's queryIntent method is calledreturn super.queryIntent(intent, resolvedType, defaultOnly, userId);
    }

---->[IntentResolver#queryIntent]------------
public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,int userId) {
    String scheme = intent.getScheme();

    ArrayList<R> finalList = new ArrayList<R>();

    final boolean debug = localLOGV || ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) ! = 0);if (debug) Slog.v(
        TAG, "Resolving type=" + resolvedType + " scheme=" + scheme
        + " defaultOnly=" + defaultOnly + " userId=" + userId + " of " + intent);

    F[] firstTypeCut = null;
    F[] secondTypeCut = null;
    F[] thirdTypeCut = null;
    F[] schemeCut = null;

    // If the intent includes a MIME type.then we want to collect all of
    // the filters that match that MIME type.
    if(resolvedType ! = null) { int slashpos = resolvedType.indexOf('/');
        if (slashpos > 0) {
            final String baseType = resolvedType.substring(0, slashpos);
            if(! baseType.equals("*")) {
                if(resolvedType.length() ! = slashpos+2 || resolvedType.charAt(slashpos+1) ! =The '*') {
                    // Not a wild card, so we can just look for all filters that
                    // completely match or wildcards whose base type matches.
                    firstTypeCut = mTypeToFilter.get(resolvedType);
                    if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTyp
                    secondTypeCut = mWildTypeToFilter.get(baseType);
                    if (debug) Slog.v(TAG, "Second type cut: "
                            + Arrays.toString(secondTypeCut));
                } else {
                    // We can match anything with our base type.
                    firstTypeCut = mBaseTypeToFilter.get(baseType);
                    if (debug) Slog.v(TAG, "First type cut: " + Arrays.toString(firstTyp
                    secondTypeCut = mWildTypeToFilter.get(baseType);
                    if (debug) Slog.v(TAG, "Second type cut: "
                            + Arrays.toString(secondTypeCut));
                }
                // Any */* types always apply, but we only need to do this
                // if the intent type was not already */*.
                thirdTypeCut = mWildTypeToFilter.get("*");
                if (debug) Slog.v(TAG, "Third type cut: " + Arrays.toString(thirdTypeCut
            } else if(intent.getAction() ! = null) { // The intent specified anytype ({@literal *}/*).  This
                // can be a whole heck of a lot of things, so as a first
                // cut let's use the action instead. firstTypeCut = mTypedActionToFilter.get(intent.getAction()); if (debug) Slog.v(TAG, "Typed Action list: " + Arrays.toString(firstType } } } // If the intent includes a data URI, then we want to collect all of // the filters that match its scheme (we will further refine matches // on the authority and path by directly matching each resulting filter). if (scheme ! = null) { schemeCut = mSchemeToFilter.get(scheme); if (debug) Slog.v(TAG, "Scheme list: " + Arrays.toString(schemeCut)); } // If the intent does not specify any data -- either a MIME type or // a URI -- then we will only be looking for matches against empty // data. if (resolvedType == null && scheme == null && intent.getAction() ! = null) { firstTypeCut = mActionToFilter.get(intent.getAction()); if (debug) Slog.v(TAG, "Action list: " + Arrays.toString(firstTypeCut)); } FastImmutableArraySet
      
        categories = getFastIntentCategories(intent); if (firstTypeCut ! = null) { buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, firstTypeCut, finalList, userId); } if (secondTypeCut ! = null) { buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, secondTypeCut, finalList, userId); } if (thirdTypeCut ! = null) { buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, thirdTypeCut, finalList, userId); } if (schemeCut ! = null) { buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, schemeCut, finalList, userId); } sortResults(finalList); if (debug) { Slog.v(TAG, "Final result list:"); for (int i=0; i
      Copy the code