Android Intent详解

什么是Intent

翻译就是意图,就是你想做的事情,比如我想成为资深攻城狮,具体的就是在Activity中我想跳转到下一个Activity中,或者我想开启服务,我想发送广播,都是需要用到Intent(意图)的。

理解

就是你想做的事,列如跳转到对应的活动,开启服务,发送广播等等。

类型

意图类型定义用于
显式意图调用Intent.setComponent()或Intent.setClass()方法明白指定了组件名的Intent为显式意图一般内部
隐式意图没有明白指定组件名的Intent为隐式意图一般外部

注:
没有绝对的用于内外部之分,显示意图可通过(包名,Activity的完整类路径)访问其它应用。
另外,Android 5.0以后规定必须显式启动Service。

1.显式意图

调用Intent.setComponent()或Intent.setClass()方法明白指定了组件名得Intent为显式意图。
如:

Intent intent = new Intent();  
 intent.setAction(Activity1.this,Activity2.class);
 intent.putExtra("name",name);//通过意图传递数据
startActivity(intent);   

其中还包括通过包名去启动

Intent intent = new Intent();
intent.setClassName("待启动Activity的包名","待启动Activity的完整类路径")//包名getPackageName()
intent.putExtra("name",name);//通过意图传递数据
startActivity(intent);//跳转到另一个Activity

如何接收传过来的数据呢?

Intent intent1=getIntent();//获取传递过来的意图
intent.getStringExtra("name");//获取前一个Activity传递过来的数据

其中还包括回调数据式传值跳转:startActivityForResult()方法

Intent _intent = new Intent(MainActivity.this,TwoActivity.class);
intent.putExtra(key, value);
// 第二个参数是请求码,只要是一个唯一值
startActivityForResult(intent, 1234);

我们在看看TwoActivity.class中的回传数据的代码

Intent intent = new Intent();
intent.putExtra("name","张三");
setResult(RESULT_OK,intent);
this.finish();

数据回传之后肯定我们的MainActivity.class中要有接收的方法,我们看看接收方法onActivityResult()

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    switch (requestCode) {
        case 1234:
            if (resultCode == RESULT_OK) {
                String name= intent.getStringExtra("name");
                Log.d(TAG, "onActivityResult: "+name);
            }
            break;
        default:
    }

onActivityResult()方法带有三个参数,
第一个参数requestCode,即我们在启动活动时传入的请求码。
第二个参数resultCode,即我们在返回数据时传入结果码。
第三个参数data,即携带着返回数据的Intent。
由于在一个活动中有可能调用startActivityForResult()方法去启动很多不同的活动,每一个活动返回的数据都会回调到onActivityResult()这个方法中,因此我们首先要做的就是通过检查requestCode的值来判断数据来源。确定数据是从TwoActivity返回的之后,我们再通过resultCode的值来判断处理结果是否成功。最后从data中取值并打印出来,这样就完成了向上一个活动返回数据的工作。

上面讲的是两种简单的数据intent传递方式,那如果数据多怎么办,没事我们可以用到序列化,绑定Bundle 对象进行处理
1.两种方式
Bundle.putSerializable(Key,Object);  //实现Serializable接口的对象  
Bundle.putParcelable(Key, Object); //实现Parcelable接口的对象
2.步骤

1.创建序列化类
Book.class,其中要重新的方法很多,但我还是推荐大家用Parcelable,因为它比Serializable在内存消耗上要少太多了,作为攻城狮怎么可以偷懒去使用Serializable?Serializable的使用很简单,直接实现接口就行,不想Parcelable要重写很多方法。

public class Book implements Parcelable{
	private String bookName;
	private String author;
	private int publishDate;
	 
	public Book(){
	  
	}
	 
	public String getBookName(){
	 return bookName;
	}
	 
	public void setBookName(String bookName){
	 this.bookName = bookName;
	}
	 
	public String getAuthor(){
	 return author;
	}
	 
	public void setAuthor(String author){
	 this.author = author;
	}
	 
	public int getPublishDate(){
	 return publishDate;
	}
	 
	public void setPublishDate(int publishDate){
	 this.publishDate = publishDate;
	}
	 
	@Override
	public int describeContents(){
	 return 0;
	}
	 
	@Override
	public void writeToParcel(Parcel out, int flags){
	 out.writeString(bookName);
	 out.writeString(author);
	 out.writeInt(publishDate);
	}
	 
	public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){
	  
	     @Override
	 public Book[] newArray(int size){
	  return new Book[size];
	 }
	  
	 @Override
	 public Book createFromParcel(Parcel in){
	  return new Book(in);
	 }
	};
	 
	public Book(Parcel in){
	 //如果元素数据是list类型的时候需要: lits = new ArrayList<?> in.readList(list); 否则会出现空指针异常.并且读出和写入的数据类型必须相同.如果不想对部分关键字进行序列化,可以使用transient关键字来修饰以及static修饰.
	 bookName = in.readString();
	 author = in.readString();
	 publishDate = in.readInt();
	}
}

2.再看看我们传递和接收的代码

//传递
Book book = new Book();
book.setBookname("Darker");
book.setBookauthor("me");
book.setPublishDate(20);
Bundle bundle = new Bundle();
bundle.putParcelable("book", book);
Intent intent = new Intent(MainActivity.this,AnotherActivity.class);
intent.putExtras(bundle);
//接收
Intent intent = getIntent();
Bundle bun = intent.getExtras();
Book book = bun.getParcelable("book");
Log.d(TAG, "AnotherActivity: "+book);

显式意图工作原理:
就是从当前上下文跳转到指定活动,或者启动指定服务,发送指定广播。

显式意图非常easy。此处就不再赘述。

2.隐式意图

没有明白指定组件名得Intent为隐式意图。android系统会依据隐式意图中设置的动作(action)、类别(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。

如调用电话拨号:

Intent intent = new Intent();
intent.setAction("android.intent.action.CALL");  
intent.setData("Uri.parse("tel:") + mobile");//mobile为电话号码(是数字)   
startActivity(intent);

通过动作名称(可自定义):

<intent-filter>
   <action android:name="android.intent.yinsiyitu.action"/>
   <category android:name="android.intent.category.DEFAULT"/>
   <data android:mimeType="application/person"/>
   <data android:scheme="jianren" android:host="www.ggl.com"/>
</intent-filter>

调用方式

Intent intent = new Intent();
intent.setAction("android:intent.yinsiyitu.action");
intent.addCategory(Intent.CATEGORY_DEFAULT);
//intent.setData(Uri.parse(jianren://www.ggl.com));//会清除前面所有set的type
//intent.setType("application/person");//会清除前面所有的set的data
//这是setData和setType两全的方法,另外如果上面的Activity定义了host,则这里一定也要指定
intent.setDataAndType(Uri.parse("jianren://www.ggl.com"),"application/person");
//如果上面的Activity没有定义host,则Uri.parse("jianren:");至少要写到冒号,不可以只写Uri.parse("jianren")
startActivity(intent);

注:
若intent.setDataAndType(Uri.parse(“jianren://www.ggl.com”),“application/person”);

分开写,即:intent.setData(),intent.setType()(括号里的东西略)时,就算是都匹配也会报错。

原因:在setType()文档中有一句话。This method automatically clears any data that was previously set by setData(Uri).也就是说。当设置了setType时会自己主动清除setData中的内容。

所以。解决方法:写成intent.setDataAndType(Uri.parse(“itcast://www.itcast.cn/person”), “image/gif”);这样就正确了。

工作原理:
当您隐式地启动一个service或activity时,Intent会根据其中的内容,匹配其他组件中manifest文件的Intent-filter,启动符合条件的组件,并把Intent中的参数传过去,如果有多个intent-filter满足条件,那么系统会弹出一个对话框,由用户决定启动哪个组件。

  1. 首先Activity A利用传入的Intent调用startActivity();

  2. 系统会根据该Intent的条件搜索Android系统中所有匹配的组件。

  3. 若找到了匹配intent的intent-filters所属的组件(Activity B),则启动该组件,并回调onCreate()方法,同时将Intent传递过去。intent-filters是manifest文件中组件内部的一个标签,该标签描述了组件具备什么特性,如果您未配置intent-filters,那个该组件只能被显式启动。

Intent使用要求

创建Intent对象(Building an Intent)

Intent中包含了目标组件需满足的特性。Intent中应包含以下信息:
目标组件的名字。

  1. 对于显式启动,这是不可缺省的,您可以使用Intent的构造方法传入组件名称,也可以调用setComponent(), setClass(), setClassName()这些方法传入组件名;

  2. 若是隐式启动,这是可选的,但intent应包含其他信息(actioncategorydata);

隐式启动中的action

是一个可以指明目标组件行为的字符串。action很大程度上决定了category和data中应传入的信息;您也可以在自己的应用程序组件中指定action,以便让其他应用程序启动自己的组件。对应action中字符串,不建议使用硬编码的形式,而应在所属组件的类中设置为常量。

常见的action有:

  1. ACTION_VIEW:用ACTION _VIEW启动的activity一般可以向用户展示一些信息,比如启动一个相册APP中展示图片的activity,或是启动一个地图APP中展示地址信息的activity。

  2. ACTION_SEND:一般需要向通过ACTION _SEND启动的activity 附带着发送一些信息,这些信息由由目标activity决定该发送给谁,比如社交类APP或是发送邮件的APP。

您可以将action作为参数传入Intent的构造方法或setAction()方法中。

如需定义在自己的组件中定义action,应以应用的包名作为前缀,比如:
staticfinalStringACTION_TIMETRAVEL=”com.example.action.TIMETRAVEL”;

隐式启动中的data

一个URI对象是一个引用的data的表现形式,或是data的MIME类型;data的类型由Intent的action决定,比如说若action是ACTION_EDIT,那么data的URI应指向一个可编辑的文件。

当创建一个Intent时,除了为data指定URI以外,还应该指定data的MIME类型,比如说,一个用于展示图片的activity是不能用来放音乐的,如果您要启动这个activity,就需要将data的MIME类型指定为"image/png"、"image/jpeg"等。有些时候,从data的URI中就能推断出MIME的类型,比如当一个URI的schema是"content://"时,表明该URI指向了设备内部的一个文件并由ContentProvider管理着,系统可以根据该文件推断出data的MIME类型。

您可以调用setData()方法设置URI,调用setType()方法设置MIME类型,或调用setDataAndType()方法同时设置URI和MIME类型。

请注意: 如果您需要同时设置URI和MIME类型,只能调用setDataAndType()方法,而不能分别调用setData()和setType(),因为调用setData()时会首先将setType()中的内容置空,反之亦然( they each nullify the value of the other)
上面有提到再强调一下。

隐式启动中的category

是一个字符串,表示目标组件的附加信息,大部分intent不需要category。以下是依稀而常用的category:

  1. CATEGORY_BROWSABLE:表示目标activity可以被网页上的某个链接启动,如图片activity或e-mail信息activity。
  2. CATEGORY_LAUNCHER:目标activity是任务栈的第一个activity,也就是应用程序的启示activity。

您可以将category参数传入addCategory()方法中

总结

目前博主也就学到了这些,因为我感觉够用,我后续的成长中我会更深入的学习并分享给大家
这篇博客借鉴了很多官方文档原文。
个人也是推荐Android初学者看官网文档,虽然这很艰苦,但是这具有权威性的文档,是你想成为Android高级攻城狮的必经之路
和我一起加油吧,与你共勉。

付:
Intent官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值