Reprint this column, please indicate the source, respect the original. Article blog address: Dao Long’s blog

This article has been published exclusively by guolin_blog, an official wechat account

In this article, the implicit start of an Activity is analyzed again.

Some people might say, isn’t it easy to implicitly launch activities? What’s not to understand? Not to mention this early, there is still a big hole to climb when it comes to implicit booting, unless, of course, you are an experienced developer.

This article, we start from the simplest, step by step introduction, I believe that this way, it will be easier to read.

When we start a campaign, there are two ways. 1. Display startup; 2. Implicit start.

First, let’s take a look at two very simple small cases (implementing phone calls).

We also provide a TextView in the layout file to prompt you to input the phone number, input the number in EditText, click the button at the same time, get the number entered by the user, and start the phone call function.

The main activity code is simple:

MainActivity:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Set click listening for the button        / / 1.Get the button object        Button bt = (Button) findViewById(R.id.bt_call);//ButtonA class isViewSubclass, downward transformation stronger.        / / 2.Set the listener        bt.setOnClickListener(new MyListener());
    }

    class MyListener implements View.OnClickListener {

        //This method is called when the button is clicked        @Override
        public void onClick(View v) {
            //Gets the number entered by the user            EditText et = (EditText) findViewById(R.id.et_phone);
            String phone = et.getText().toString();

            //We need to tell the system what we're doing: I'm going to call            //Create an intention object            Intent intent = new Intent();
            //Make a phone callACTION_CALLEncapsulate the intent object            intent.setAction(Intent.ACTION_CALL);
            //Set who to call            intent.setData(Uri.parse("tel:" + phone));//thistelI need to make a phone call. Otherwise there will be no call function, because this is set up in the call list file"agreement"
            //Tell the system what you're doing.Enable the system call function.            startActivity(intent);
        }}}

Run as follows:





This is so simple, I think the code will rot in my stomach.

Well, that’s pretty simple, so let’s go ahead and look at a simple code for customizing the launch activity.

(2) Customize the Activity and start it implicitly

As we all know, if you want to customize an activity to implicitly start another activity, you need to add an intent-filter to that activity.

You can specify the actions that the current activity can respond to by configuring the contents of <intent-filter> under the <activity> TAB

And category, open androidmanifest.xml and add the following code:

<activity android:name=".NextActivity">
    <intent-filter>
        <action android:name="com.itydl"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>




In the <action> tag, we specify that the current Activity can respond to the com.itydl action. We can write whatever we like inside. Its addition adds an action to our Activity. The <category> tag, on the other hand, contains additional information that more precisely specifies the categories that the current activity can respond to in the Intent.
The action set in the intent must match “com.ityDL” exactly< Action > and <category> can respond to an Intent only if the content in both matches the action and category specified in the Intent. . We have a way, the android intent. The category. The DEFAULT is a kind of DEFAULT category, in the call startActivity () method will automatically add the category to the intent of (check all system source code, We don’t need to worry too much about the potential pitfalls of a category.

The principle for Action is as follows: When StartActivity() runs, the Activity will go through all the manifest files in the system to find a matching Activity in the corresponding Action(“”). If there is a matching Activity in the corresponding Action(in this case NextActivity), This launches NextActivity.

Now that NextActivity has an action, our MainActivity will add a button to start it implicitly. As follows:

mNext = (Button) findViewById(R.id.bt_next);
mNext.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent();
        intent.setAction("com.itydl");
        startActivity(intent);
    }});


Run the program and find that it can start normally. We noticed that the first example also added a setData() when it started the call function. So, our custom can also add data. Modify the NextActivity configuration code of the manifest file as follows:

<intent-filter>
    <action android:name="com.itydl"/>
    <data android:scheme="ydl"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>

At this point, we run the program again and find that the program crashes. This is because our implicit launch code does not exactly match the content below <intent-filter> in the manifest. In order for the match to succeed, we also need to set data in the code. Back to the first example, we also know why the call function to set setData, but also because the phone manifest file source code has this data tag.

Here is a brief introduction of the system to add data below the tag:

The following can be configured in the tag. 1. Android: Scheme is used to specify the protocol part of data. 2. Android :host specifies the host name part of the data. 3. Android :port Specifies the port portion of the data, usually following the host name. 4. Android :path is used to specify the part after the host name and port, such as the content after the domain name in a web address. 5. Android :mimeType is used to specify the type of data that can be processed. The current activity can respond to an Intent only if the content specified in the tag is exactly the same as the data carried in the Intent. However, the tag usually does not specify too much content, the common ones are mimeType and scheme.

Add the following code to our implicit start button:

intent.setData(Uri.parse("ydl:qwe"));

Running programs no longer report errors.

The above content, for a beginner is must master the content. Let’s take a look at some details that might actually make it hard to implicitly start other activities!

(3) In-depth analysis of the details of implicit priming

We’ll start with custom implicit booting. Parse () : “ydl:qwe” (ydl:qwe) Based on the configuration introduction in system above, the manifest file is Android: Scheme, which is a protocol, so we set the data must start with the content after Scheme. This is “YDL” as a protocol. And then you can write “Qwe” whatever you want. For example, I changed it to the following code:

intent.setData(Uri.parse("ydl:234"));

You can still start the next activity.

So let’s go back to our original small case, which has the following code:

intent.setData(Uri.parse("tel:" + phone));


Isn’t there an agreement here? In the manifest file, the corresponding Activity must have this protocol. Let’s go to the upper source code and find the following code:

<activity android:name="OutgoingCallBroadcaster" android:permission="android.permission.CALL_PHONE" android:theme="@android:style/Theme.NoDisplay" android:configChanges="orientation|keyboardHidden"> <! -- CALL action intent filters, for the various ways of initiating an outgoing call. --> <intent-filter> <action android:name="android.intent.action.CALL" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="tel" /> </intent-filter> <intent-filter android:icon="@drawable/ic_launcher_sip_call"> <action android:name="android.intent.action.CALL" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="sip" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.CALL" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="voicemail" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.CALL" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/phone" /> <data android:mimeType="vnd.android.cursor.item/phone_v2" /> <data android:mimeType="vnd.android.cursor.item/person" /> </intent-filter> </activity>Copy the code

We see android: Permission is the permission we call to specify. Let’s go down to the first intent-filter


The action of the android: name = “android. Intent. Action. CALL” / > is not in our code to set up the action (intent. SetAction (intent. ACTION_CALL);) ?

At this point, I believe that you can grasp this detail. Then continue to climb down the pit ~

We find that there are too many intent-filters in the list of call broadcaster. How do we know which intent-filter will be matched to initiate the call? In fact, it’s pretty simple, because in the manifest intent-filter it means that there are several different ways that we can start this activity, this call activity. It doesn’t matter which way we use it, either way. So let’s emulate this situation by adding a few intent-filters to the custom launch activity. After reading the following, the pit will climb.

(4) Configure different intent-filters for your own activity by imitating the source code

First, we continue adding intent-filter to the manifest

<intent-filter>
    <action android:name="com.itydl2"/>
    <data android:scheme="ydl2"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>

Two intent – filter at this time, we in order to verify, just start the activities of code change:

Intent intent = new Intent();
intent.setData(Uri.parse("ydl2:234"));
intent.setAction("com.itydl2");
startActivity(intent);

So we’re going to change it to ydl2, so it starts with this intent-filter. Can start activities normally.

Note that the start interaction code must match one of the intent-filters to start the activity properly, otherwise an error will be reported. That’s why, and trust us it’s easy to understand why.

Follow up:

Can we configure multiple intent-filters, as well as multiple data and actions in the manifest? (This is also true in many sources). Let’s try the listing file again with the following changes:

<intent-filter>
    <action android:name="com.itydl2"/>
    <action android:name="com.itydl3"/>
    <action android:name="com.itydl4"/>
    <action android:name="com.itydl5"/>
    <data android:scheme="ydl2"/>
    <data android:scheme="ydl3"/>
    <data android:scheme="ydl4"/>
    <data android:scheme="ydl5"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>

There are multiple data and multiple actions added here. In fact, in the code where we start the activity, we only need to configure any data and any action to successfully start the activity. There is no problem with active code even if it is written like this:

Intent intent = new Intent();
intent.setAction("com.itydl2");
intent.setData(Uri.parse("ydl4:234"));
startActivity(intent);

The event is started successfully.

And finally, just a little bit more. The common Android :mimeType attribute

SetData puts the data in it, and it passes the data to the target Activity, where the target Activity gets the data in it by getIntent(). Android :mimeType is used to define what type of data you want setData to pass. For example, when passing text data, we could write:

<intent-filter>
    <action android:name="com.itydl2"/>
    
    <data android:mimeType="text/username"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>

We first tested only Android :mimeType.

Intent intent = new Intent();
intent.setAction("com.itydl2");
intent.setType("text/username");
startActivity(intent);

At this point, the code and the manifest file match exactly. We run the program without any problems.

When android:mimeType and Android: Scheme exist together, we need to pay attention

If the code first sets setData(); After setType(), the latter will clean up the former, and vice versa. This is the same principle as your goddess asking you “who would you save first if your mother or I fell into the water?” We need to set both Scheme and mimeType in the setDataAndType() method to match the intent-filter in the corresponding manifest. For example, the code in my manifest file is:

<intent-filter>
    <action android:name="com.itydl2"/>
    <data android:scheme="ydl2"/>
    <data android:mimeType="text/username"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>

So when we start, we need to go through

intent.setDataAndType(Uri.parse("ydl2:qwe")."text/username");

This will match the contents of the listing file perfectly, and actiiVity can be started normally.



Finally finished, I believe that after reading this article you will be more clear about the principle of implicit priming activities. To launch any future interaction, just look at the contents of the manifest file for that activity, and you can easily open it implicitly!



Finally, I wish you all a merry Christmas!





Friends who like me can follow my blog column.

You can also open wechat to search the public number Android programmer development guide or scan the qr code below the public number to read more Android articles.

Photo of wechat official account: