美文网首页
认识Intent

认识Intent

作者: WindMajor | 来源:发表于2017-09-22 19:58 被阅读3次

    Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent一般可被用于启动活动、启动服务、以及发送广告等场景。

    Intent的用法分为显式Intent和隐式Intent两种。接下来详细解析。

    1.了解Intent的构造方法

    Intent的方法有很多,通过认识构造方法,我们能够窥探到Intent的不同用法。

    1.空构造方法:

        public Intent() {
        }
    

    2.根据另一个Intent创建的构造方法

        public Intent(Intent o) {
            this.mAction = o.mAction;
            this.mData = o.mData;
            this.mType = o.mType;
            this.mPackage = o.mPackage;
            this.mComponent = o.mComponent;
            this.mFlags = o.mFlags;
            this.mContentUserHint = o.mContentUserHint;
            if (o.mCategories != null) {
                this.mCategories = new ArraySet<String>(o.mCategories);
            }
            if (o.mExtras != null) {
                this.mExtras = new Bundle(o.mExtras);
            }
            if (o.mSourceBounds != null) {
                this.mSourceBounds = new Rect(o.mSourceBounds);
            }
            if (o.mSelector != null) {
                this.mSelector = new Intent(o.mSelector);
            }
            if (o.mClipData != null) {
                this.mClipData = new ClipData(o.mClipData);
            }
        }
    

    3.由一条Action创建的构造方法

        public Intent(String action) {
            setAction(action);
        }
    

    其中的setAction()方法如下:

        public Intent setAction(String action) {
            mAction = action != null ? action.intern() : null;
            return this;
        }
    

    4.通过Action和Uri共同创建的构造方法

        public Intent(String action, Uri uri) {
            setAction(action);
            mData = uri;
        }
    

    5.通过Context和Class文件创建的构造方法

        public Intent(Context packageContext, Class<?> cls) {
            mComponent = new ComponentName(packageContext, cls);
        }
    

    6.大杂烩,通过Action、Uri、Context还有Class文件创建的构造方法

        public Intent(String action, Uri uri,
                Context packageContext, Class<?> cls) {
            setAction(action);
            mData = uri;
            mComponent = new ComponentName(packageContext, cls);
        }
    

    通过这些构造方法,我们需要从中学习到,不同构造方法的Intent,其作用是不同的。

    1.参数要求为Context以及Class的

    接下来会在构造方法中会创建出ComponentName对象,这个是Android的组件,是可以具体到某个具体的组件的,这种就是显式的使用方法。

    2.参数要求为Action的

    接下来会在构造方法中调用setAction()方法,也就是给mAction赋值,对应到AndroidManifest文件中的<intent-filter><action>标签,在启动时,如果配置了相同action和category的Activity都可能被启动起来,如果匹配到多个,会弹出对话框让用户手动选,这种就是隐式的使用方法。

    2.隐式使用Intent的注意事项

    • 每个Intent中只能指定一个action,但是可以指定多个category。

    • startActivity()方法中会自动将"android.intent.category.DEFAULT"这个默认的category添加到Intent中,如果被启动的Activity声明的category正好就是默认的话,可以不用写。

    • 在AndroidManifest文件中声明Activity的时候,如果希望这个Activity是用隐式的方式被启动,那么在<intent-filter>标签中,必须要添加上这一条:

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

    如果AndroidManifest文件中没有这一条,那么即使Action能够匹配上依然会崩溃。
    如下:

               <intent-filter>
                   <action android:name="com.company.windmajor.JUMP"/>
    
                   <category android:name="android.intent.category.DEFAULT"/>
               </intent-filter>
    

    代码调用:

                    Intent intent = new Intent();
                    intent.setAction("com.company.windmajor.JUMP");
                    startActivity(intent);
    
    • 如果有自己限定category的需求,那么可以先添加上面一点中提到的DEFAULT的category,然后再定义自己的category。然后在java代码中添加自己定义的category。如下:
                <intent-filter>
                    <action android:name="com.company.windmajor.JUMP"/>
    
                    <category android:name="android.intent.category.DEFAULT"/>
                    <category android:name="com.company.windmajor.category.JUMP"/>
                </intent-filter>
    
    

    代码中的调用:

                    Intent intent = new Intent();
                    intent.setAction("com.company.windmajor.JUMP");
                    intent.addCategory("com.company.windmajor.category.JUMP");
                    startActivity(intent);
    

    3.更多隐式Intent的用法

    使用Intent,还可以启动其他App的Activity,这将使得Android多个应用程序之间的功能共享成为了可能。
    这里介绍几个用法:Intent.ACTION_VIEW和Intent.ACTION_DIAL

    (1)Intent.ACTION_VIEW

    这个Action是系统定义的Action,可以将带有浏览器功能的App给打开,使用代码如下:

            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setData(Uri.parse("http://www.baidu.com"));
                    startActivity(intent);
                }
            });
    
    

    这段代码的效果就是打开浏览器,然后访问百度网。
    setData()的方法接受Uri对象,主要用于指定当前Intent正在操作的数据,而这些数据通常都是以字符串的形式传入到Uri.parse()方法中解析产生的。
    与此对应,我们还可以在<intnet-filter>标签中再配置一个<data>标签,用于更精确的指定当前活动能够相应什么类型的数据。<data>标签中,主要可以配置以下内容。

    • android:scheme 指定数据的协议部分,如上面代码里的http部分
    • android:host 指定数据的主机名部分,如上面代码里的www.baidu.com部分
    • android:port 指定数据的端口部分,一般紧随在主机名之后
    • android:path 指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容
    • android:mimeType 指定可以处理的数据类型,允许使用通配符的方式进行指定。

    只有<data>标签中指定的内容和Intent中携带的Data完全一致是,当前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"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/text_view_two"
            android:text="Activity Two"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    
    

    然后创建一个新的Activity:

    public class TwoActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_two);
    
        }
    }
    

    最后非常重要的是一定要在AndroidManifest文件中注册新的Activity

            <activity android:name=".TwoActivity">
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:scheme="http" />
                </intent-filter>
            </activity>
    

    这样运行起来之后,点击刚才的那个按钮,就可以看到选择启动程序的一个列表,列表中包括浏览器还包括我们刚刚创建新Activity的这个程序。当然只有打开浏览器,我们才能看到百度网页面的各种广告,点击我们自己的程序是不能看到的,因为我们的程序也没有写处理浏览登陆的代码。

    (1).Intent.ACTION_DIAL

    使用代码如下:

            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(Intent.ACTION_DIAL);
                    intent.setData(Uri.parse("tel:10086"));
                    startActivity(intent);
                }
            });
    

    4.Activity之间的数据互传

    Intent可以用来启动Activity,当然也是可以传递数据的,为了方便Activity之间的数据通信,Activity提供了putExtra()方法的重载,可以传递许多中类型的数据。
    使用代码如下:

            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, TwoActivity.class);
                    intent.putExtra("EXTRA_DATA","Hello SecondActivity");
                    startActivity(intent);
                }
            });
    

    这里putExtra()方法的第一个参数是“键”,第二个参数是真正的“值”,键通常都是String类型的,值可以有很多种类型。那么这个地方传递了,别的地方如何取呢?

            Intent intent = getIntent();
            String data = intent.getStringExtra("EXTRA_DATA");
    

    只需要在被启动的Activity里面使用如上的代码即可。当然要知道传的时候是什么类型,取的时候必须要能类型匹配上。不然不行。

    当上一个Activity传递数据给下一个Activity,那么下一个Activity如何将数据结果传递回给上一个Activity呢?这里需要介绍一下startActivityForResult()方法。
    这个方法需要两个参数,第一个参数是启动Intent,第二个参数是启动的请求码,只要是唯一的整型数字即可。

            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, TwoActivity.class);
                    intent.putExtra("EXTRA_DATA", "Hello SecondActivity");
                    startActivityForResult(intent, 1);
                }
            });
    

    当用户在界面TwoActivity完成了相应的操作,得到了想要的数据,需要将这个数据返回给第一个MainActivity,只需要下面这么做:

            twoButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent();
                    intent.putExtra("EXTRA_RETURN", "This is the result...");
                    setResult(RESULT_OK, intent);
                    finish();
                }
            });
    

    我们看到上面的Intent仅仅只是用来传递数据,setResult()方法很重要,第一个参数用于向前一个Activity返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个系统定义好的值表示成功与失败,第二个参数是把带有数据结果的Intent对象传递回去。最后使用finish()方法将当前的Activity销毁。

    由于我们是使用startActivityForResult()方法来启动的第二个Activity,这种启动方法需要实现一个特殊的方法才可以使用第二个Activity返还回来的数据。

        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            switch (requestCode) {
                case 1:
                    if (resultCode == RESULT_OK) {
                        String returnedData = data.getStringExtra("EXTRA_RETURN");
                        Log.i("MainActivity", returnedData);
                    }
                    break;
                default:
                    break;
            }
        }
    
    

    这个方法有三个参数,第一个参数requestCode是启动第二个Activity时的启动码,我们设置的是1,第二个参数resultCode是从第二个Activity返还回来时的结果码,一般有两种RESULT_OK和RESULT_CANCELED,第三个参数data就是带着数据的Intent对象。

    以上就是Intent的一些简单的特性和使用方法,希望共同勉励。

    案例和知识点都来源于郭霖的《第一个行代码》,在此特别感谢郭老师,希望大家看完本篇文章后,希望全面了解的可以购买郭老师的书。

    相关文章

      网友评论

          本文标题:认识Intent

          本文链接:https://www.haomeiwen.com/subject/xwwfextx.html