应用核心Intent
应用核心Intent
1、Intent对象
用户需要从一个Activity切换到另一个,则必须使用Intent来激活。实际上,Activity、Service和Broadcast Receiver这3种核心组件都需要使用Intent来进行激活。Intent用于相同或者不同应用程序组件间的后期运行时绑定。
- Intent对象可以传递给Context.startActivity(或Activity.startActivity ForResultO方法来启动Activity或者让已经存在的Activity去做其他任务。Intent对象也可以作为Activity.setResultO方法的参数,将信息返回给调用startActivityForResultO方法的Activity.
- Intent对象可以传递给Context..startServiceO方法来初始化Service或者发送新指令到正在运行的Service..类似的,Intent对象可以传递Context..bindServiceO方法来建立调用组件和目标Service之间的链接。它可以有选择地初始化没有运行的服务。
- 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代码中进行设置,而是使用
过滤器中包含的域与Intent对象中动作、数据和分类域相对应。过滤器对于隐式Intent在这3个方面分别进行测试。仅有通过全部测试时,ntent对象才能发送给拥有过滤器的组件。由于组件可以包含多个过滤器,Intent对象在一个过滤器上失败并不代表不能通过其他测试。下面对这些测试进行详细介绍。
- 动作测试
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.EDIT" />
</intent-filter>
如上所示,尽管ntent对象仅定义一个动作,在过滤器中却可以列出多个。列表不能为空,即过滤器中必须包含至少一个
动作,结果如下:
如果过滤器没有包含任何动作,即没有让对象匹配的东西,则任何对象都无法通过该测试。
如果过滤器至少包含一个动作,则没有指定动作的对象自动通过该测试。
- 种类测试
配置文件中的
<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与否
均可)。
- 数据测试
<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>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程