关于Bundle

注意到Activity的onCreate()方法的签名是protected void onCreate(Bundle savedInstanceState),其参数是一个Bundle实例。

Bundle以键值对的形式来存储数据,类似于Map,以便在Activity之间传递数据、状态信息。Bundle的键均为String类型,值可以是各种基本类型及可序列化的对象类型。

Bundle的常用方法

构造方法:

Bundle()、Bundle(Bundle b)等

get系列根据键获取对应值的方法:

Object  get(String key)

boolean  getBoolean(String key)

boolean  getBoolean(String key, boolean defaultValue)

Bundle  getBundle(String key)

char  getChar(String key)

char  getChar(String key, char defaultValue)

int  getInt(String key)

int  getInt(String key, int defaultValue)

Serializable  getSerializable(String key)

等等

注:根据键到Bundle实例中查找对应值,若存在,则返回对应的值。不存在时,带有默认值的方法,返回传入的默认值;不带默认值的方法返回响应的零值,如false、null、0.0f、0等。

put系列存放键值对的方法:

void  putAll(Bundle map)

void  putBoolean(String key, boolean value)

void  putBundle(String key, Bundle value)

void  putChar(String key, char value)

void  putDouble(String key, double value)

void  putSerializable(String key, Serializable value)

等等

其他方法:

boolean  isEmpty()  判断Bundle实例是否为空。

Set<String>  keySet()  返回当前Bundle实例中key的集合。

int  size()  返回Bundle实例键值对的数目。

关于Intent

注意到,在前面的程序中,从一个Activity启动另一个Activity,总是这样做:

 Intent intent = new Intent(FirstActivity.this,  SecondActivity.class);

 startActivity(intent);

可知,Intent可以用来表示一种启动Activity的意图,用来启动另一个Activity。

其实,Intent是一种消息传递机制,可以在应用程序中使用,也可以在应用程序之间使用。不仅可以用来启动Activity还可以用来启动Service和BroadcastReceiver。而且,还可以利用Intent与被启动的组件进行数据传输,信息交换。

Intent的构造方法

Intent()

Intent(Intent o)

Intent(String action)

Intent(String action, Uri uri)

Intent(Context packageContext, Class<?> cls)

Intent(String action, Uri uri, Context packageContext, Class<?> cls)

Intent中的主要属性

  private String mAction;

  private HashSet<String> mCategories;

  private Uri mData;

  private String mType;

  private ComponentName mComponent;

  private Bundle mExtras;

注意到,源码中属性的命名方式都是以m打头,表示这是一个member。

1)Component属性:指明了该Intent要启动的组件。该属性是一个ComponentName类型的对象,其构造方法有:

public ComponentName(String pkg, String cls)

pkg应为Manifest.xml中声明的Manifest节点的package属性声明的包名

cls应为要启动组件的完整类名:包名.类名的形式。

public ComponentName(Context pkg, String cls)

pkg为要启动的上下文环境,可以传入当前Activity实例的引用,如this。若是在内部类中,则应为MainActivity.this(注:MainActivity为当前Activity类名)

cls为要启动组件的完整类名:包名.类名的形式。

public ComponentName(Context pkg, Class<?> cls)

pkg为要启动的上下文环境,可以传入当前Activity实例的引用,如this。若是在内部类中,则应为MainActivity.this(注:MainActivity为当前Activity类名)

cls为要启动组件,如SecondActivity.class(注:SecondActivity为要启动的组件名)

总结:这三个构造方法都是要指定启动的上下文环境和一个要启动组件的完整类限定名,即传入包名.类名。由于在Android应用中包名是作为应用的唯一标识,所以包名与代表应用上下文环境的Context是一一对应的。

如:

第一个构造代码:

 Intent intent1 = new Intent();

 intent1.setComponent(new ComponentName("cn.csc.lifecycle", "cn.csc.lifecycle.NormalActivity"));

 startActivity(intent1);

第二个构造代码:

 Intent intent1 = new Intent();

 intent1.setComponent(new ComponentName(this, "cn.csc.lifecycle.NormalActivity"));

 startActivity(intent1);

第三个构造代码:

 Intent intent1 = new Intent();

 intent1.setComponent(new ComponentName(this, NormalActivity.class));

 startActivity(intent1);

Intent提供了一种简化的设置Component属性的方法,即:

Intent(Context packageContext, Class<?> cls)

这也是我们之前一直用的一种方式。

 startActivity(new Intent(this, NormalActivity.class));

注意:设置了Component属性的Intent因为已然明确指定要启动的组件,故而被称之为显式Intent。当然,有显式Intent,肯定就有隐式Intent。

隐式Intent不指定Component属性,而是通过设置其他属性,来制定所要启动的组件应该具备的条件,然后,符合Intent其他属性所指定的条件的组件就会被启动。这时,运行时会使用一个称为“Intent解析”的过程来动态选择符合条件的组件。在Intent中设置要启动组件所需要具备的条件,就要用到Intent的mAction和mCategories等属性。

2)Action和Category属性

源代码中属性的声明如下:

private String mAction;

private HashSet<String> mCategories;

可知,Action属性是一个普通的字符串,只能有一个,Category属性也是字符串,可以有多个,共同存放在一个名为mCategories的HashSet中。

其中,Action表示该Intent所要启动的组件应该能完成的抽象动作,比如Intent.ACTION_VIEW,可以完成查看动作,Intent.ACTION_DIAL可以完成拨号的动作等等。Category属性则用于为Action增加额外的附加类别信息。

如何让自己的组件具备Intent所要求的条件呢?

这里就需要在Manifest.xml中,注册应用所需组件,如Activity时,给Activity节点添加上<action>和<category>子节点,设置这两个节点的name属性,使其值与Intent中Action属性和Category属性一一对应即可。

如:

 Intent intent1 = new Intent();

 intent1.setAction("myaction");

 startActivity(intent1);

要使此时自己定义的NormalActivity能被启动,则应在Manifest.xml中这样配置:

 <activity android:name=".NormalActivity">

             <intent-filter >

                 <action android:name="myaction"/>

             </intent-filter>

 </activity>

运行程序,发现如下错误:

查看LogCat错误信息:

android.content.ActivityNotFoundException: No Activity found to handle Intent { act = myaction}

找不到能够接收处理action为”myaction”的Intent意图。

但是,我们明明在<intent-filter>中声明了的。

其实,这里只要修改一下<intent-filter>即可:

 <intent-filter >

                 <action android:name="myaction"/>

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

 </intent-filter>

这样,就能正常启动NormalActivity。

原因在于:当我们不明确设定Intent的Category属性时,其值默认为Intent.CATEGORY_DEFAULT常量,该常量值为"android.intent.category.DEFAULT"。

注意:Intent最多只能设置一个Action以及0~n个Category(注:0个其实,也是一个Intent.CATEGORY_DEFAULT常量);但是在Manifest.xml中为组件注册时,在<intent-filter>中可以指定多个<action>,多个<category>。只要该组件所注册的<action>和<category>能涵盖在Intent中设置的所有Action和Category即可被启动。

如上例中,修改<intetn-filter>如下:

 <intent-filter >

                 <action android:name="myaction"/>

                 <action android:name="myaction1"/>

                 <category android:name="mycategory"/>

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

 </intent-filter>

仍能被上面的Intent启动。

如,修改Intent如下:

 Intent intent1 = new Intent();

 intent1.setAction("myaction");

 intent1.addCategory("mycategory");

 startActivity(intent1);

仍然符合条件。

注意,设置Action的方式是setAction(),而由于Category可以有多个,设置的方式不是setCategory()而是addCategory()。

Intent也提供了对应的构造方法来简化Action的设置:

Intent(String action)

Intent(String action, Uri uri)

其中第二个构造函数的第二个参数为Uri对象,这就涉及到Intent的Data属性。

3)Data属性

Data属性用于向Action属性所表示的动作提供所要操作的数据,如Action为Intent.ACTION_CALL表示要拨号,它对应的Data就应当为要拨打的号码。

Data属性接受一个Uri对象,通常以字符串”scheme://host:port/path”的形式表示:

如:”http://www.baidu.com” ,”tel:110”等。

如,修改Intent代码:

 Intent intent1 = new Intent();

 intent1.setAction(Intent.ACTION_CALL);

 intent1.setData(Uri.parse("tel:110"));

 startActivity(intent1);

将启动模拟器的拨号器,并拨打110

当然,在运行程序之间需要在Manifest.xml中Manifest节点下,添加<uses-permisson>子节点,配置该程序所需要的拨打电话的权限:

<uses-permission  android:name="android.permission.CALL_PHONE"/>

此时,如果修该NormalActivity的<intent-filter>

添加如下Action: <action android:name="android.intent.action.CALL"/>,想要让它也能被Intent启动,发现还是只启动拨号器。

这是因为,Intent设置了Data属性,要想让NormalActivity能被该Intent启动,也要在<intent-filter>中设置<data>子节点:<data android:scheme="tel"/>

此时,由于有多个组件具备Intent启动所要求的条件,故而出现选择列表,让用户来选择要启动的组件。

运行效果:

注意到,上面<data>子节点只设置了scheme属性,则所有scheme属性为tel的Data属性都能符合条件。

若修改Intent:

 Intent intent1 = new Intent();

 intent1.setAction(Intent.ACTION_VIEW);

 intent1.setData(Uri.parse("http://www.baidu.com"));

 startActivity(intent1);

此时,会启动浏览器,浏览http://www.baidu.com

修改NormalActivity的<intent-filter>添加

<action android:name="android.intent.action.VIEW"/>

修改<data>子节点: <data android:scheme="http"/>

重新运行:

若在<data>节点中设置android:host=“www.baidu.com”此时,也是可以启动NormalActivity的。但是,若Intent的Data属性换成”http://www.taobao.com”此时就不能启动NormalActivity了,因为它的<data>不符合条件。

只有<data>的属性与Data一致时,才能被Intent所启动。一般只指定android:scheme属性即可,不会给出太具体的属性。

注意:<intent-filter>节点中可以有0~N个<action>、0~N个<category>、0或1个<data>。

4)Type属性:用于指定该Data所指定的Uri对应的MIME类型,可以是任何自定义的MIME类型,只要符合abc/xyz格式的字符串就行。如:text/html等。

Data属性与Type属性会相互覆盖:谁最后被设置,谁就起作用,之前被设置的就被覆盖。若Data被覆盖,则getData()返回null,若Type被覆盖,getType()返回null。

 Intent intent1 = new Intent();

 intent1.setAction(Intent.ACTION_VIEW);

 intent1.setData(Uri.parse("http://www.baidu.com"));

 intent1.setType("text/html");

此时,调用intent1.getData()返回值为null。data节点若设置如下:

<data android:mimeType="text/html"/> 则能被intent1启动。但是若:

<data android:scheme="http" android:mimeType="text/html"/> ,这时就不能启动了,因为比Type值多出来个scheme属性。

若是希望同时设置Data和Type属性,则必须要使用setDataAndType()方法,如:

intent1.setDataAndType(Uri.parse("http://www.baidu.com"), "text/html");

此时,浏览器一定会被启动,若要NormalActivity也能被启动,其<data>节点,一定要同时设置android:scheme和android:mimeType属性:

<data  android:scheme="http" android:mimeType="text/html"/>

5)Extras属性

注意到private Bundle mExtras; mExtras的类型是Bundle。所以Intent可以借助其Bundle类型的mExtras属性在Activity之间进行数据传递。

Bundle  getExtras()  获取mExtras属性。

Intent  putExtras(Bundle extras)  设置mExtras属性。

可以调用Bundle的相关方法设置好要保存的键值对,然后再把Bundle实例传给putExtras()方法。Intent提供了更简单的键值对操作方式:

putExtra(String name, XXX  value) :向Intent中存入name-value的键值对,实际上是存入mExtras中。XXX表示不同的数据类型,如同Bundle中的putInt(),putDouble()等putXXX()。

getXxxExtra(String name):从Intent中按照key获取对应的值。实际上是到mExtras这个Bundle实例中去获取值。如同Bundle中的getInt(),getDouble()等getXxx()。

利用Intent在Activity之间传递数据:

前面曾经提到过Activity中有个名为getIntent()的方法,可以用来获取启动该Activity的Intent实例。

如,在MainActivity中获取启动它的Intent实例,并调用其toString()方法,将其设置为第一个按钮的text属性:

 protected void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         setContentView(R.layout.main_layout);

         Log.i("LIFECYCLE","onCreate");

         Button btnNormal = (Button) findViewById(R.id.normal);

         Button btnDialog = (Button) findViewById(R.id.dialog);

         btnNormal.setOnClickListener(this);

         btnDialog.setOnClickListener(this);

         btnNormal.setText(getIntent().toString());

 }

从MainActivity向NormalActivity传递一个名为”data”,值为” data given by MainActivity”的数据:

 Intent intent1 = new Intent(this, NormalActivity.class);

 intent1.putExtra("data", "data given by MainActivity");

 startActivity(intent1);

在NormalActivity中获取这个值,并将其设置为TextView的text属性:

 protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.first_layout);

            TextView tv = (TextView) findViewById(R.id.tv);

            tv.setText(getIntent().getStringExtra("data"));

 }

如果想要让被启动的Activity返回数据给启动它的那个Activity要怎么做呢?

startActivity()启动别的Activity之后就完全不再理它了,此时,就需要另外一个方法:

startActivityForResult(Intent intent, int requestCode):该方法用于根据intent参数启动一个Activity,并期望在被启动的Activity结束时,获得一个返回结果。

调用startActivityForResult()之后,被启动的Activity结束后返回前一个Activity时,会回调它的onActivityResult(int requestCode, int resultCode, Intent intent),其中,requestCode代表请求码,resultCode代表被启动Activity设置的返回结果码,intent里面包含了返回的数据。

被启动的Activity要给启动它的Activity返回数据时,需要调用setResult()方法设置要返回的数据。

如:MainActivity中使用startActivityForResult()启动NormalActivity,并重写onActivityResult()方法,接收NormalActivity传回的数据。

 Intent intent1 = new Intent(this, NormalActivity.class);

 intent1.putExtra("data", "data given by MainActivity");

 startActivityForResult(intent1,0);
 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {

            // TODO Auto-generated method stub

            super.onActivityResult(requestCode, resultCode, intent);

            if(intent == null){

                  Log.i("tag","null");

            }else{

                  Log.i("tag",intent.getStringExtra("res"));

            }

 }

NormalActivity重写返回按钮按下的回调函数onBackPressed()向MainActivity返回数据:

 public void onBackPressed() {

            Log.i("tag","back pressed");

            setResult(Activity.RESULT_OK,getIntent().putExtra("res", "resultxxx"));

            super.onBackPressed();

 }

此时,要注意,如果super.onBackPressed()放在该方法的第一句,无论后面设置什么值都不会被成功传递回去。

查看Activity的onBackPressed()方法的源代码,即可发现原因:

 public void onBackPressed() {

         if (!mFragments.popBackStackImmediate()) {

             finish();

         }

 }

这个方法会直接调用finish()直接结束该Activity实例。

 public void finish() {

         if (mParent == null) {

             int resultCode;

             Intent resultData;

             synchronized (this) {

                 resultCode = mResultCode;

                 resultData = mResultData;

             }

             if (false) Log.v(TAG, "Finishing self: token=" + mToken);

             try {

                 if (resultData != null) {

                     resultData.prepareToLeaveProcess();

                 }

                 if (ActivityManagerNative.getDefault()

                     .finishActivity(mToken, resultCode, resultData)) {

                     mFinished = true;

                 }

             } catch (RemoteException e) {

                 // Empty

             }

         } else {

             mParent.finishFromChild(this);

         }

 }

阅读finish()的源码可以发现:若发现当前Activity需要返回数据,则直接传递null回去,然后结束掉当前Activity实例。

所以,无论我们在super.onBackPressed()后设置任何返回数据都不会被真正传回。

当然,也可以不调用super.onBackPressed(),在设置完成要返回的数据之后,自己调用一个finish()方法即可。

android菜鸟学习笔记10----Intent及<intent-filter>的更多相关文章

  1. Android:日常学习笔记(10)———使用LitePal操作数据库

    Android:日常学习笔记(10)———使用LitePal操作数据库 引入LitePal 什么是LitePal LitePal是一款开源的Android数据库框架,采用了对象关系映射(ORM)的模式 ...

  2. android菜鸟学习笔记29----Android应用向用户发送提示信息的方式总结

    常见的向用户发送提示信息的方式有3种,分别为: 1)发送Toast信息 2)弹出对话框 3)发送通知 总结如下: 方式1:发送Toast信息: 这种方式最简单,在之前的学习中多次使用过.Toast是在 ...

  3. android菜鸟学习笔记26----Android广播消息及BroadcastReceiver

    1.广播类型: Android中的广播有两种类型:标准广播和有序广播.其中,标准广播是完全异步发送的广播,发出之后,几乎所有的广播接收者都会在同一时刻收到这条广播消息,因而,这种类型的广播消息是不可拦 ...

  4. android菜鸟学习笔记28----Android中的Service生命周期及本地和远程服务绑定的实现

    Service是Android中长期在后台运行的没有界面的组件,使用服务的优势在于:能够提高进程的优先级,系统不容易回收掉进程,即便回收了,内存充足的时候,会把进程重新创建. 1.服务的简单使用示例: ...

  5. android菜鸟学习笔记8----Activity(一)

    Activity是android应用程序中重要的组件之一,常听到的android四大组件是Activity.Service.BroadcastReceiver和ContentProvider.它间接继 ...

  6. android菜鸟学习笔记3----关于AndroidMainfest.xml

    每个android项目都包含一个AndroidMainfest.xml文件,它包含了组成应用程序的每一个Acitivity.Service.Content Provider和Broadcast Rec ...

  7. android菜鸟学习笔记24----与服务器端交互(一)使用HttpURLConnection和HttpClient请求服务端数据

    主要是基于HTTP协议与服务端进行交互. 涉及到的类和接口有:URL.HttpURLConnection.HttpClient等 URL: 使用一个String类型的url构造一个URL对象,如: U ...

  8. android菜鸟学习笔记21----ContentProvider(一)ContentProvider的简单使用

    ContentProvider是Android四大组件之一,它用来封装数据,并通过ContentResolver接口将数据提供给其他应用.只有当需要在多个应用之间共享数据时才会用到ContentPro ...

  9. android菜鸟学习笔记20----Android数据存储(四))Android数据库操作

    Android内置了一个名为SQLite的关系型数据库,这是一款轻量型的数据库,操作十分简便.SQLite与别的数据库不同的是,它没有数据类型.可以保存任何类型的数据到你所想要保存的任何表的任何列中. ...

随机推荐

  1. python对象的复制问题

    list 的拷贝问题: 1, >>> a [1, 2] >>> b=a[:] >>> b [1, 2] >>> b[0]=20 ...

  2. POI 2014 HOTELS (树形DP)

    题目链接 HOTELS 依次枚举每个点,以该点为中心扩展. 每次枚举的时候,从该点的儿子依次出发,搜完一个儿子所有的点之后进行答案统计. 这里用了一个小trick. #include <bits ...

  3. POJ 1239 Increasing Sequences [DP]

    题意:略. 思路:进行两次dp. 第一次dp从前向后,用dp[x]表示从第x位向前dp[x]位可构成一个数字,且与前面的数组符合题意要求.最后求的dp[n]即为最后一个数字的长度. 而题目还有要求,所 ...

  4. 转:ospf学习-----SPF最短路径算法

    ospf学习-----SPF最短路径算法 常见的路由协议比如RIP.IGRP.BGP是距离矢量协议,OSPF和ISIS是数据链路状态协议.矢量协议路由器只知道本身和与自身相连的接口路由信息,矢量图只是 ...

  5. 【转】java:多网卡环境下获取MAC地址

    http://blog.csdn.net/10km/article/details/78569962 JDK6以后 java.net.NetworkInterface提供了完整的方法用于获取网络设备信 ...

  6. my -> mysql on duplicate key update使用总结

    CREATE TABLE `t_duplicate` ( `a` int(11) NOT NULL, `b` int(255) DEFAULT NULL, `c` int(255) DEFAULT N ...

  7. Vuex 通俗版教程

    作者 Yeaseon 已关注 2017.03.16 16:44* 字数 1245 阅读 243评论 2喜欢 4 本文基本上是官方教程的盗版,用通俗易懂的文字讲解Vuex,也对原文内容有删减. 如果你对 ...

  8. EasyMvc入门教程-高级控件说明(18)弹出框控件

    前面两节介绍了信息框与对话框,实际开发中如果我们遇到更复杂的要求,比如要求在弹出框里显示另外的网址,如下所示: 实现代码如下: @Html.Q().Popup().Text("我可以嵌套网页 ...

  9. 解决Linux下AES解密失败

    前段时间,用了个AES加密解密的方法,详见上篇博客AES加密解密. 加解密方法在window上測试的时候没有出现不论什么问题.将加密过程放在安卓上.解密公布到Linuxserver的时候,安卓将加密的 ...

  10. 值得推荐的android开发框架简单介绍

    一些总结出来的Android高速开发框架,所有都是开源框架,附带项目地址,是开发学习的绝佳资料. Direct-Load-apk项目 项目主页地址:http://www.kymjs.com/ 功能:D ...