应用核心Intent

应用核心Intent

1、Intent对象

用户需要从一个Activity切换到另一个,则必须使用Intent来激活。实际上,Activity、Service和Broadcast Receiver这3种核心组件都需要使用Intent来进行激活。Intent用于相同或者不同应用程序组件间的后期运行时绑定。

  1. Intent对象可以传递给Context.startActivity(或Activity.startActivity ForResultO方法来启动Activity或者让已经存在的Activity去做其他任务。Intent对象也可以作为Activity.setResultO方法的参数,将信息返回给调用startActivityForResultO方法的Activity.
  2. Intent对象可以传递给Context..startServiceO方法来初始化Service或者发送新指令到正在运行的Service..类似的,Intent对象可以传递Context..bindServiceO方法来建立调用组件和目标Service之间的链接。它可以有选择地初始化没有运行的服务。
  3. Intent对象可以传递给Context..sendBroadcast0、Context..sendOrderedBroadcastO:或Context.send-
    StickyBroadeastO等广播方法,使其被发送给所有感兴趣的BroadcastReceiver。

在Intent对象中,包含了接收该Intent的组件感兴趣的信息(如执行的操作和操作的数据)以及Android系统感兴趣的信息(如处理该Intent的组件的类别和任何启动目标Activity的说明)。原则上讲,Intent包含组件名称、动作、数据、种类、额外和标记等内容,下面进行介绍。

1.1、组件名称(ComponentName)

组件名称是指intent目标组件的名称。它是一个ComponentName对象,由目标组件的完全限定类名(如com.android.TestActivity)和组件所在应用程序配置文件中设置的包名(如com.android)组合而成。组件名称的包名部分和配置文件中设置的包名不必匹配。组件名称是可选的。如果设置,ntent对象会被发送给指定类的实例;如果没有设置,Android使用Intent对象中的其他信息决定合适的目标。组件名称可以使用setComponentO、setClassO或setClassName(方法设置,使用getComponent()方法读取

1.2、动作(action)

Action是一个字符串,用来表示将要执行的动作。在广播Intent中,Action用来表示已经发生即将报告的动作。在intent类中,定义了一系列动作常量,其目标组件包括Activity和Broadcast两类。

除了预定义的动作,开发人员还可以自定义动作字符串来启动应用程序中的组件。这些自定义的字符串应该包含一个应用程序包名作为前缀,如com.android..SHOW COLOR.动作很大程度上决定了Intent其他部分的组成,特别是数据(data)和额外(extras)部分,就像方法名称决定了参数和返回值。因此,动作名称越具体越好,并且将它与Intent其他部分紧密联系。换句话说,开发人员应该为组件能处理Intent对象定义完整的协议,而不是单独定义一个动作。Intent对象中的动作使用setAction()方法设置,使用getAction()方法读取。

1.3、数据(Data)

Data表示操作数据的URI和MME类型。不同动作与不同类型的数据规范匹配。例如,如果动作是ACTION EDIT,数据应该是包含用来编辑的文档的URI;如果动作是ACTION CALL,数据应该是包含呼叫号码的tel:URI。类似的,如果动作是ACTION VIEW而且数据是http:URL,接收的Activity用来下载和显示URI指向的数据。在将Intent与处理它的数据的组件匹配时,除了数据的URL,也有必要了解其MIME类型。例如,能够显示图片数据的组件不应用来播放音频文件。在多种情况下,数据类型可以从URI中推断,尤其是content::URI。它表示数据存在于设备上并由ContentProvider控制。但是,类型信息也可以显式地设置到Intent对象中。setData()方法仅能指定数据的URI,setType()方法仅能指定数据的MIME类型,setDataAndType(方法可以同时设置URI和MIME类型。使用getDataO方法可以读取URI,使用getType(方法可以读取类型。

1.4、种类(Category)

Category是一个字符串,其中包含了应该处理当前Intent的组件类型的附加信息。在Intent对象中可以增加任意多个种类描述。与动作类似,在Intent类中也预定义了一些种类常量,其说明如表4.3所示。

addCategory0方法将种类增加到Intent对象中,removeCategory(方法删除上次增加的种类,getCategories()方法获得当前对象中包含的全部种类。

1.5、额外(Extras)

Extras是一组键值时,其中包含了应该传递给处理Intent的组件的额外信息。就像一些动作与特定种类的数据URI匹配,而一些与特定额外匹配。例如,动作为ACTION TIMEZONE CHANGED的Intent用time-zone额外来表示新时区;动作为ACTION HEADSET PLUG的Intent用state额外来表示耳机是否被插入,以及用name额外来表示耳机的类型。如果开发人员自定义一个SHOW COLOR动作,则应该包含额外来表示颜色值。Intent对象中包含了多个putXXXO方法(如putExtraO方法)用来插入不同类型的额外数据,也包含了多个getXXX()方法(如getDoubleExtra()方法)来读取数据。这些方法与Bundle对象有些类似。实际上,额外可以通过putExtras(和getExtras(方法来作为Bundle设置和读取。

1.6、标记(Flags)

Flags表示不同来源的标记。多数用于指示Android系统如何启动Activity(如Activity属于哪个Task)以及启动后如何对待(如它是否属于近期的Activity列表)。所有标记都定义在ntent类中。

2、范例

在Activity之间使用Intent传递信息

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="userNmae"
        android:id="@+id/name"/>
    <EditText
        android:layout_width="300px"
        android:layout_height="wrap_content"
        android:inputType="textPersonName"
        android:id="@+id/inputname"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="passWord"
        android:id="@+id/psw"/>
    <EditText
        android:layout_width="300px"
        android:layout_height="wrap_content"
        android:inputType="textPassword"
        android:id="@+id/inputpsw"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ok"
        android:id="@+id/button"/>

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/name"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/psw"/>

</LinearLayout>
package com.example.intentproject001;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

    private Button ok;
    private EditText name;
    private EditText psw;

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

        name = (EditText)findViewById(R.id.inputname);
        psw = (EditText)findViewById(R.id.inputpsw);
        ok = (Button)findViewById(R.id.button);

        ok.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.putExtra("com.android.USERNAME", name.getText().toString());
                intent.putExtra("com.android.PASSWORD", psw.getText().toString());
                intent.setClass(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}
package com.example.intentproject001;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;

import androidx.annotation.Nullable;

public class SecondActivity extends Activity {

    private TextView name;
    private TextView psw;

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

        Intent intent = getIntent();
        String inputname = intent.getStringExtra("com.android.USERNAME");
        String inputpsw = intent.getStringExtra("com.android.PASSWORD");

        name = (TextView)findViewById(R.id.name);
        psw = (TextView)findViewById(R.id.psw);

        name.setText(inputname);
        psw.setText(inputpsw);
    }
}

3、范例2

返回系统Home桌面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button"
        android:text="back"/>

</LinearLayout>
package com.example.intentproject002;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        Button viewById = (Button) findViewById(R.id.button);
        viewById.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_MAIN);
                intent.addCategory(Intent.CATEGORY_HOME);
                startActivity(intent);
            }
        });
    }
}

4、Intent的使用

4.1、Intent过滤器

Activity、Service和BroadcastReceiver能定义多个Intent过滤器来通知系统它们可以处理哪些隐式Intent。每个过滤器描述组件的一种能力以及该组件可以接收的一组ntent。。实际上,过滤器接收需要类型的Intent、拒绝不需要类型的Intent仅限于隐式Intent。对于显式Intent,无论内容如何,总可以发送给其目标,过滤器并不干预。

对于能够完成的工作及显示给用户的界面,组件都有独立的过滤器。

Intent过滤器是ntentFilter类的实例。然而,由于Android系统在启动组件前必须了解组件的能力,Intent过滤器通常不在Java代码中进行设置,而是使用标签写在应用程序的配置文件(AndroidManifest.xml)中(唯一的例外是调Context.registerReceiver()方法动态注册BroadcastReceiver的过滤器,它们通常直接创建为IntentFilter对象)。

过滤器中包含的域与Intent对象中动作、数据和分类域相对应。过滤器对于隐式Intent在这3个方面分别进行测试。仅有通过全部测试时,ntent对象才能发送给拥有过滤器的组件。由于组件可以包含多个过滤器,Intent对象在一个过滤器上失败并不代表不能通过其他测试。下面对这些测试进行详细介绍。

  1. 动作测试
<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <action android:name="android.intent.action.EDIT" />
</intent-filter>

如上所示,尽管ntent对象仅定义一个动作,在过滤器中却可以列出多个。列表不能为空,即过滤器中必须包含至少一个标签,否则会阻塞所有Intent.为了通过该测试,tet对象中定义的动作必须与过滤器中列出的一个动作匹配。如果对象或者过滤器没有指定
动作,结果如下:

如果过滤器没有包含任何动作,即没有让对象匹配的东西,则任何对象都无法通过该测试。

如果过滤器至少包含一个动作,则没有指定动作的对象自动通过该测试。

  1. 种类测试

配置文件中的标签将分类作为.子标签列出,例如:

<intent-filter>
    <category android:name="android.intent.category.LAUNCHER" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

为了让Intent通过种类测试,ntent对象中每个种类都必须与过滤器中定义的种类匹配。在过滤器中可以增加
额外的种类,但是不能删除任何Intent中的种类。
因此原则上讲,无论过滤器中如何定义,没有定义种类的Intent总是可以通过该项测试。然而,有一个例外。
Android默认所有通过startActivity(方法传递的隐式Intent包含一个种类android.intent.category.DEFAULT
(CATEGORY DEFAULT常量)。因此,接收隐式Intent的Activity必须在过滤器中包含
android,intent.category.DEFAULT(包含android.intent.action.MAN和android,intent.category.LAUNCHER设置的是
一个例外。它们标示Activity作为新任务启动并且显示在启动屏幕上,包含android.intent..category.DEFAULT与否
均可)。

  1. 数据测试
<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http"/>
</intent-filter>

每个标签可以指定URI和数据类型(MME媒体类型)。URI可以分成scheme、host、port和path几个独立的部分:

scheme://host:port/path
例如下面的URI:
content://com.example.project:200/folder/subfolder/etc

其中,scheme是content;.host是com.example..project;port是20O;path是folder/subfolder/etc.host和port一起组成了URI授权,如果host没有指定,则忽略pot。

这些属性都是可选的,但是相互之间并非完全独立。如果授权有效,则scheme必须指定。如果path有效,则scheme和授权必须指定。

当Intent对象中的URI与过滤器中的URI规范比较时,它仅与过滤器中实际提到的URI部分相比较。例如,如果过滤器仅指定了scheme,所有具有该scheme的URI都能匹配该过滤器;如果过滤器指定了scheme和授权而没指定path,则不管path如何,具有该scheme和授权的URI都能匹配;如果过滤器指定了scheme、授权和path,则具有相同scheme、授权和path的URI能够匹配。然而,过滤器中的path可以包含通配符来允许部分匹配。

标签中的type属性指定数据的MME类型。在过滤器中,这比URI更常见。Internet对象和过滤器都能使用“”通配符来包含子类型,如“text/”或者“audio/*”。

5、范例

使用包含预定义动作的隐式Intent

在Activity中使用包含预定义动作的隐式Intent启动另外一个Activity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="BUtton"
        android:id="@+id/button"/>

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="111111111"
        android:id="@+id/textView"/>

</LinearLayout>
package com.example.intentproject003;

import android.app.Activity;
import android.os.Bundle;

import androidx.annotation.Nullable;

public class NextActivity extends Activity {

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

package com.example.intentproject003;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_VIEW);
                startActivity(intent);
            }
        });
    }
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.intentproject003">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.IntentProject003">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".NextActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

说明:由于有多种匹配ACTION_VIEW的方式,因此需要用户进行选择

6、范例2

使用包含自定义动作的隐式Intent

在范例1中,讲述了使用系统中预定义的动作来定义Intent.。开发人员还可以根据需要自定义动作。本范例将在范例1的基础上进行修改,使用自定义动作来启动隐式Intent。

修改MainActivity中的Intentd的动作内容

package com.example.intentproject003;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setAction("test_action");
                startActivity(intent);
            }
        });
    }
}

修改AndroidManifest.xml中第二个活动的过滤器的动作内容

<activity android:name=".NextActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="test_action"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

启动应用程序,此时并没有让用户选择处理隐式Intent的组件,而是直接跳转到第二个Activity。

7、实例

7.1、使用Intent拨打电话

安卓6之后出现运行时权限功能,一些危险权限需要在运行是进行申请,在需要时通过用户手动授权

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <EditText
        android:layout_width="400px"
        android:layout_height="wrap_content"
        android:id="@+id/edit"
        android:inputType="number"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="call"
        android:id="@+id/button"/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.intentproject004">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.IntentProject004">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
</manifest>
package com.example.intentproject004;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    EditText text;

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

        Button call = (Button) findViewById(R.id.button);
        text = (EditText) findViewById(R.id.edit);

        call.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (ContextCompat.checkSelfPermission(MainActivity.this,
                        Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]{Manifest.permission.CALL_PHONE}, 1);
                }else {
                    call();
                }
            }
        });
    }

    private void call() {
        try {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:" + text.getText().toString()));
            startActivity(intent);
        }catch (Exception e){
            Toast.makeText(MainActivity.this, "111", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    call();
                } else {
                    Toast.makeText(MainActivity.this, "11111", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }
}

7.2、使用Intent打开网页

package com.example.intentproject005;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intent);
            }
        });
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button"
        android:id="@+id/button"/>

</LinearLayout>
posted @   凉菜花生  阅读(123)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示