Intent知识总结

此文章为个人的知识总结,如有错误,欢迎指正.

作用

1.Intent(意图,目的)是android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据.

2.Intent一般可以被用于启动活动,启动服务,发送广播等场景.

3.Intent可以分为两种:显式Intent和隐式Intent.

显式Intent

显式Intent是程序内部跳转活动最常用的一种方式,其用法也很简单:

Intent intent = new Intent(PackageContext , Class);
startActivity(intent);

其中PackageContext参数为本活动所能提供的上下文,如this , MainActivity.this , Class参数为待启动的活动类,如Main2Activity.class

隐式Intent

隐式Intent相对于显式Intent来说就比较复杂,它不仅能够在程序内部跳转活动,还可以在程序间跳转活动,我们需要掌握的就是程序间跳转的规则.

一.先来看看基本的用法:

Intent intent = new Intent();
intent.setAction("android.intent.action.XX");
intent.addCategory("android.intent.category.xx");
startActivity(intent);

可以看到,我们调用了Intent类的两个方法,setAction()和addCategory(),我们知道,Intent是用来跳转活动的,所以不难看出setAction()方法是用来指向名称为android.intent.action.XX的活动,那addCategory()又是什么?

Category的中文意思种类,范畴的意思,你可以把它当作是某个活动的所属类别,我们在利用startActivity()方法启动Intent时,会先在系统里找寻类别为android.intent.category.xx,名字为android.intent.action.XX的活动,只有系统存在满足这两个条件的活动,才可以正常的跳转,否则系统将报异常.

需要指出的是,一个活动可以有多个Category,但是只能有一个Action名,并且在程序内外部,都可以存在名字,类别相同的活动,那你可以会有问,如果存在相同的名字的活动名,那程序在跳转活动时该选择哪一个呢?答案是系统会给你自己选,我们应该都有遇到下图的这种情况:

二.那如果我们自己创建的活动,该去哪里设置活动的名称和类别呢?答案在AndroidManifest.xml中,找到活动对应的activity标签:

<activity
            android:name=".Main2Activity"
            android:label="@string/title_activity_main2">
            <intent-filter>
                <action android:name="com.example.krehizilin.myapplication.Main2Activity"/>
                <category android:name="com.example.krehizilin.myapplication.MY_CATEGORY" />
            </intent-filter>
</activity>

action和category标签一定是放在intent-filter标签中的,其android:name属性分别就是活动名和类名,其值是可以随便取的,当是,为了统一规范,我们一般都是以活动所在的包名来开头的.

action标签只能有一个,category标签可以多个.

注意:

android.intent.category.DEFAULT是一种默认的category,我们在调用startActiivity()方法隐式启动活动时,会类似的默认添加一行intent.addCategory("android.intent.category.DEFAULT");代码,这意味着,我们需要在启动的活动添加<category android:name="android.intent.category.DEFAULT"/>,否则就会报异常.

Intent intent = new Intent();
intent.setAction("android.intent.action.XX");
intent.addCategory("android.intent.category.xx");
intent.addCategory("android.intent.category.DEFAULT");//默认添加此行代码,实际上是没有的
startActivity(intent);
<activity
            android:name=".Main2Activity"
            android:label="@string/title_activity_main2">
            <intent-filter>
                <action android:name="com.example.krehizilin.myapplication.Main2Activity"/>
                <category android:name="com.example.krehizilin.myapplication.MY_CATEGORY" />
                <!--添加此行代码,否则将会报异常-->           
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
</activity>

此外还有一点比较特殊,就是我们隐式跳转到主活动(<action android:name="android.intent.action.MAIN" />)时,并不需要为主活动添加<category android:name="android.intent.category.DEFAULT"/>,同样可以正常跳转.

典例探究

我们应该都有用过以下代码来实现拨打电话,那它具体是怎么实现的呢?

Intent intent = new Intent(Intent.ACTION_DIAL);
Uri data = Uri.parse("tel:110");
intent.setData(data);
startActivity(intent);

以上代码的主要问题就是setData()方法,其有两个作用,一是类似Category用来匹配对应的活动(过程比Category稍微复杂),二是可以用来传递数据.

如果你不懂Uri和此方法的使用,请阅读此博客的进阶部分:https://blog.csdn.net/Krehizi/article/details/81842608

--------------------------------------------------------------------------------------------------------------------------------------------------------------

有了以上知识,我们便可以继续研究,首先,Intent.ACTION_DIAL的真实值为android.intent.action.DIAL,所以此意图指向的是名为android.intent.action.DIAL的活动,然后通过此setDate()方法再次约束此意图,使之指向符合Uri为tel:110的活动.

由于获取系统电话软件的源代码比较麻烦,我们自己创建一个活动来代替系统电话软件的拨打界面,其活动清单为:

<activity android:name=".Main2Activity">
            <intent-filter>
                <action android:name="android.intent.action.DIAL" />

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

                <data android:scheme="tel"/>
               
            </intent-filter>
</activity>

可以看到,action,category,data都能够匹配上,所以此活动我们能够正常打开,并且对应的就是打开拨打电话的界面.

之后便在我们代替系统电话软件的活动中,编写逻辑代码,获取到传递过来的Uri的中的电话号码,然后实现拨打电话的过程(拨打电话的实现代码省略,只模拟获取到电话号码):

Intent intent = getIntent();
if (intent != null){
     Uri uri = intent.getData();
     Toast.makeText(Main2Activity.this, uri.getSchemeSpecificPart(),Toast.LENGTH_SHORT).show();
}

uri.getSchemeSpecificPart()方法获取到的便是110了(此方法的用法在上面提到的博客上有讲解).

so,这样我们利用隐式启动的知识,弄清楚在别的软件上调用系统的电话软件拨打电话的过程了.

传递数据

向下个活动传递数据

活动MainActivity传递:

Button transferData = (Button) findViewById(R.id.transferData);
transferData.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v) {
        String data = "this is data";
        Intent intent = new Intent(MainActivity.this , SecondActivity.class);
        intent.putExtra("extra_data" , data);
        MainActivity.this.startActivity(intent);
    }
});

活动SecondActivity接收:

Button gettingData = (Button) findViewById(R.id.gettingData);
gettingData.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v) {
        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Toast.makeText(SecondActivity.this , "值为 : " + data , Toast.LENGTH_LONG).show();
    }
});

向上个活动传递数据

MainActivity活动启动Main2Activity活动:

Button button = (Button) findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(MainActivity.this , Main2Activity.class);
            startActivityForResult(intent , 1);	//启动
        }
    });

Main2Activity活动返回数据:

button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent();
            intent.putExtra("key" , "123456789");
            setResult(RESULT_OK , intent);	//返回
            finish();
        }
    });

当使用setResult()方法时,MainActivity的onActivityResult()方法被回调:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode){
        case 1 :
            if (resultCode == RESULT_OK){
                Log.d(TAG, "onActivityResult: " + data.getStringExtra("key"));
            }
    }
}

Bundle

Bundle主要用于传递数据(也可以是对象,对象数组),它保存的数据是以key-value(键值对)的形式存在的。

当Bundle传递的是对象或对象数组时,必须实现Serializable 或Parcelable接口。

Bundle提供了各种常用类型的putXxx()/getXxx()方法,用于读写基本类型的数据。

Intent intent = new Intent(PackageContext , Class);

Bundle bundle = new Bundle();          //得到bundle对象  
bundle.putString("key1", "value");     //存入数据,String类型
bundle.putInt("key2", 175);            //存入数据,int类型
bundle.putSerializable("object",object);    //存入对象

intent.putExtras(bundle);             //利用Intent的putExtras方法携带此Bundle
startActivity(intent);

-----------------------------------------------------------------------------------

在下个活动中获取数据:
Bundle bundle = getIntent().getExtras();     //读取intent的数据给Bundle对象         
String str1 = bundle.getString("key1");       //通过key得到value     
int int1 = bundle.getInt("key2");             //通过key得到value
Object object = (Object) bundle.getSerializable("object");    //通过key得到object

Intent本身就可以传递参数为何还要用Bundle呢?

Bundle只是一个信息的载体,内部其实就是维护了一个Map<String,Object>。

Intent负责Activity之间的交互,内部是持有一个Bundle的,Intent的putExtra()方法的源码:

public Intent putExtra(String name, boolean value) {
        if (mExtras == null) {
            mExtras = new Bundle();
        }
        mExtras.putBoolean(name, value);
        return this;
}

应用场景:

  • 例1:
    从A界面跳转到B界面或者C界面
    这样的话 我就需要写2个Intent 如果你还要涉及的传值的话 你的Intent就要写两遍添加值的方法。那么,如果我用1个Bundle,直接先存值,然后再存到Intent中 不就更简洁吗?

  • 例2:
    现在要把值通过Activity A经过Activity B传给Activity C。如果用Intent的话,A-B先写一遍,再在B中都取出来 然后在把值塞到Intent中,再跳到C。
    如果在A中用了 Bundle 的话,把Bundle传给B,在B中再转传到C,C就可以直接去取了。

具体看 : https://www.jianshu.com/p/e9db0797293b
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值