Android开发之Intent、广播和接收

<h1>Android开发之Intent、广播和接收</h1>
<p>/*</p>
<p>* Android开发之Intent、广播和接收</p>
<p>*</p>
<p>* Created on: 2011-8-15</p>
<p>* Author: blueeagle</p>
<p>* Email: liujiaxiang@gmail.com</p>
<p>*/</p>
<p></p>
<h2>Intent</h2>
<p> Intent是一种消息传递机制,它可以声明执行某个动作的意图,并且通常是跟一段特定的数据一起进行声明的。</p>
<p> Intent支持Android设备上可用的仁义两个应用程序组件之间的交互,不管它们是哪个应用程序的一部分都是如此。这就把一个相互独立的组件集合变成了一个互联的系统。</p>
<p> Intent最常见的一个用法是显示地(通过指定要加载的类)或隐式地(通过请求对一组数据执行某个动作)启动新活动。</p>
<p> Intent也可以用来在系统范围内广播消息。任何应用程序都可以注册一个广播接收器来监听和相应这些广播的Intent。这样就可以基于内部的、系统的或者第三方的应用程序事件,创建事件驱动的应用程序。</p>
<p> Android使用广播Intent来公布系统事件,例如,网络连接状态或者电池电量的改变。本地Android应用程序(例如拨号程序,SMS管理器)可以简单地注册监听特定的广播Itent的组件——例如,“来电”或者“接受SMS消息”,并作出相应的响应。</p>
<p></p>
<p>使用Intent来启动活动,有两种方式:</p>
<p>1. 显示地启动新的活动</p>
<p>这个是我们比较常用的,跳转Activity的时候会用到。例如:</p>
<textarea readonly name="code" class="java"> Intent intent = new Intent();

intent.setClass(WelcomeView.this, OAMainView.class);

startActivity(intent);

</textarea><p><br>
2. 隐式的Intent和延时的运行时绑定。</p>
<p>当使用这个新的隐式Intent来启动一个活动时,Android将在运行时把它解析为最适合在指定的数据类型上执行动作的类。</p>
<p>例如:如果希望让用户从应用程序中打电话,那么不必实现一个新的拨号程序,而可以用一个隐式的Intent来请求一个在电话号码上执行的动作,如下面代码:</p>
<textarea readonly name="code" class="java"> Intent intent = new Intent(Intent.ACTION_DIAL,Uri.parse("tel:777-8888"));

startActivity(intent);

</textarea><p><br>
Android会解析这个Intent,并启动一个新的活动,该活动会提供对这个电话号码进行拨号的动作。</p>
<p></p>
<p>下面介绍,从活动返回结果的相关内容。</p>
<p></p>
<p>关于StartActivity与StartActivityForResult:前者启动活动的时候,启动的活动与其父活动是不相关的,而后者的不同在于后者除了用来确定启动哪个活动的Intent之外,还需要传入一个request码。也就是说,后者启动的子Activity将带着这个码进行工作,这个码就好像是这个子Activity的一个标识。当然,当这个子活动返回结果的时候,这个码就起到了至关重要的作用。</p>
<p> 例如我们启动一个有码的Intent。(呃,看到有码,我突然邪恶了)</p>
<textarea readonly name="code" class="java"> private static final int SUB_ACTIVITY = 1;

Intent intent = new Intent();

intent.setClass(WelcomeView.this, OAMainView.class);

startActivityForResult(intent,SUB_ACTIVITY);

</textarea><p><br>
这个和常规的activity一样,这种有码的子activity也可以被显示或者隐式的调用。</p>
<p></p>
<p>例如,调用系统的联系人列表,然后在系统的联系人列表里选择一项后返回。</p>
<textarea readonly name="code" class="java"> Intent intent = new Intent(Intent.ACTION_PICK,Uri.parse("content://contacts/people"));

startActivityForResult(intent,SUB_ACTIVITY);

</textarea><p><br>
当子Activity可以关闭的时候,则在调用finish之前调用setResult,并向调用它的父Activity返回一个结果。</p>
<p>setResult方法有两个参数,分别是:结果码和代表Intent结果的有效内容。</p>
<p>结果码是运行子活动的结果——一般情况下是Activity.RESULT_OK、Activity.RESULT_CANCELED。在某些情况下,程序开发人员可能希望使用自己的响应码来处理应用程序特定的选择。setResult支持任意整数值。</p>
<p> 当一个子活动关闭的时候,会触发其父活动的onActivityResult事件处理程序。通过重写这个方法,来处理从子活动返回的结果。onActivityResult接收多个参数:</p>
<p>请求码:用来启动返回子活动。</p>
<p>结果码:用来说明结果。</p>
<p></p>
<h3>使用Intent Filter 来为隐式Intent提供服务。</h3>
<p> Intent Filter 用来注册活动、服务和广播接收器并对一个动作或者一类特定的数据进行处理。使用IntentFilter,应用程序组件会告诉Android,他们可以为其他地方的动作请求服务,包括相同应用程序的组件以及本地或者第三方的应用程序组件。</p>
<p> 要把一个应用程序组件注册为Intent处理程序,可以使用组件的清单结点中的intent-filter标签。</p>
<p> 通过在Intent Filter结点内使用标签,可以指定一个组件所支持的动作、分类和数据。</p>
<p>如下Intent Filter的例子:</p>
<textarea readonly name="code" class="html"><activity android:name=”.mytestActivity”

android:label=”test”>

<intent-filter>

<action

android:name=”com.blueeagle.intent.action.MY_TEST”>

</action>

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

<category

android:name=”android.intent.category.ALTERNATIVE_SELECTED”

/>

<data android:mimeType=”vnd.android.cursor.dir/*”/>

</intent-filter>

</activity>

</textarea><p><br></p>
<p>下面来说明一下这些东西都是干什么用的:(摘抄自Android高级编程)</p>
<p>? action</p>
<p>使用android:name特性来指定对响应的动作名。动作名必须是独一无二的字符串,所以,一个好的习惯是使用基于Java包的命名方式的命名系统。</p>
<p>?category</p>
<p>使用android:category属性用来指定在什么样的环境下动作才被响应。每个Intent Filter标签可以包含多个category标签。你可以指定自定义的种类或使用Android提供的标准值,如下所示:</p>
<p>?ALTERNATIVE</p>
<p>一个Intent Filter的用途是使用动作来帮忙填入上下文菜单。ALTERNATIVE种类指定,在某种数据类型的项目上可以替代默认执行的动作。例如,一个联系人的默认动作时浏览它,替代的可能是去编辑或删除它。</p>
<p>?SELECTED_ALTERNATIVE</p>
<p>与ALTERNATIVE类似,但ALTERNATIVE总是使用下面所述的Intent解析来指向单一的动作。SELECTED_ALTERNATIVE在需要一个可能性列表时使用。</p>
<p>?BROWSABLE</p>
<p>指定在浏览器中的动作。当Intent在浏览器中被引发,都会被指定成BROWSABLE种类。</p>
<p>?DEFAULT</p>
<p>设置这个种类来让组件成为Intent Filter中定义的data的默认动作。这对使用显式Intent启动的Activity来说也是必要的。</p>
<p>?GADGET</p>
<p>通过设置GADGET种类,你可以指定这个Activity可以嵌入到其他的Activity来允许。</p>
<p>?HOME</p>
<p>HOME Activity是设备启动(登陆屏幕)时显示的第一个Activity。通过指定Intent Filter为HOME种类而不指定动作的话,你正在将其设为本地home画面的替代。</p>
<p>?LAUNCHER</p>
<p>使用这个种类来让一个Activity作为应用程序的启动项。</p>
<p>?data</p>
<p>data标签允许你指定组件能作用的数据的匹配;如果你的组件能处理多个的话,你可以包含多个条件。你可以使用下面属性的任意组合来指定组件支持的数据:</p>
<p>?android:host</p>
<p>指定一个有效的主机名(例如,com.google)。</p>
<p>?android:mimetype</p>
<p>允许你设定组件能处理的数据类型。例如,<type android:value=”vnd.android.cursor.dir/*”/>能匹配任何Android游标。</p>
<p>?android:path</p>
<p>有效地URI路径值(例如,/transport/boats/)。</p>
<p>?android:port</p>
<p>特定主机上的有效端口。</p>
<p>?android:scheme</p>
<p>需要一个特殊的图示(例如,content或http)。</p>
<h3>对Intent Filter匹配做出响应</h3>
<p>当一个应用程序组件通过一个隐式的Intent启动的时候,它需要找到要执行的动作,以及执行这个动作所依赖的数据。</p>
<p> 可以调用getIntent方法,来提取用来启动一个组件的Intent。</p>
<textarea readonly name="code" class="java"> @Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

Intent intent = getIntent();

</textarea><p><br>
使用getData和getAction方法来查找Intent的数据和动作。使用类型安全的get<type>Extra方法来提取存储在它的附件Bundle中的额外信息。</p>
<textarea readonly name="code" class="java">String dataPath = intent.getData().toString();
String action = intent.getAction();
</textarea><h3><textarea readonly name="code" class="java">白话文</textarea></h3>
<p> 上面说的我自己看着都晕,说点白话文吧。其实这个Intent Filter为隐式的Intent提供服务主要的流程如下:</p>
<p> 启动一个Activity这个Activity可以认为是一个父Activity—>然后new一个Intent,这个new的intent需要有一个动作,而这个动作列表,Android都已经给你了,你也可以自己定义。一般情况下的动作有:(我们以ACTION_PICK作为例子)</p>
<p>ACTION_ANSWER:打开一个处理来电的活动,目前这个动作是由本地电话拨号程序进行处理的。</p>
<p>ACTION_CALL:打开一个电话拨号程序,并立即使用URI所提供的号码,拨打一个电话。通常,如果可能的话,使用Dial_Action是一种更好的方式。</p>
<p>ACTION_PICK:启动一个子活动,它可以让你从URI数据中得到一个条目。当关闭的时候,它应该向条目中返回一个执行得到的数据URI。这个活动的启动要跟取的数据有关,例如,传递content://contacts/people将会调用本地联系人列表。</p>
<p> New完这个Intent以后,就可以利用StartActivityForResult(intent,REQUIRE_CODE)</p>
<p>其中第二个参数为请求码。就是开启另外一个Activity的请求码。先不管这码什么用,就知道这个码随着startActivityForResult函数一起传给了新new的那个intent了。</p>
<p> 必要的,在AndroidManifest.xml文件里要添加一个新的Intent Filter</p>
<p align="left"> </p>
<textarea readonly name="code" class="html"><intent-filter>

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

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

<data android:path = "contacts"

android:scheme="content"/>

</intent-filter>

</textarea><p align="left"><br>
接下来就是写子Activity了。创建一个子Activity,这里就是为什么时候是隐式的原因:(我的理解是这样)</p>
<p>用getIntent()来找一个intent,然后用getData()来找一个intent的数据。</p>
<p>然后经过一系列操作以后,就用SetResult(Activity.RESULT_OK,outData);以及结束代码来结束这个子Activity,结束的时候,将把Activity.RESULT_OK传给父的Activity。</p>
<p> 在父Activity中,则通过重载onActivityResult这个函数,来处理子Activity返回回去的结果。</p>
<p> 完成测试以后需要添加一个阅读权限。</p>
<p align="left"><uses-permission android:name=<em>"android.permission.READ_CONTACTS"</em>/></p>
<p align="left"></p>
<p>多的不说了,上源码:</p>
<p><strong><em>ContactPicker.java</em></strong></p>
<p><strong><em></em></strong></p>
<textarea readonly name="code" class="java">package com.blueeagle;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;<p>/*</p>
<p>* Android开发之Intent、广播和接收</p>
<p>*</p>
<p>* Created on: 2011-8-15</p>
<p>* Author: blueeagle</p>
<p>* Email: liujiaxiang@gmail.com</p>
<p>*/
public class ContactPicker extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = new Intent();
intent = getIntent();
String dataPath = intent.getData().toString();
String action = intent.getAction(); String[] from = new String[]{People.NAME};
final Uri data = Uri.parse(dataPath+"people/");
final Cursor c = managedQuery(data,null,null,null,null);
int[] to = new int[] {R.id.itemTextView};
SimpleCursorAdapter myadapter = new SimpleCursorAdapter(this,R.layout.listitemlayout,c,from,to);
ListView lv = (ListView)findViewById(R.id.contactListView);
lv.setAdapter(myadapter);
lv.setOnItemClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?>parent,View view ,int pos,long id){
c.moveToPosition(pos);
int rowId = c.getInt(c.getColumnIndexOrThrow("_id"));
Uri outURI = Uri.parse(data.toString()+rowId);
Intent outData = new Intent();
outData.setData(outURI);
setResult(Activity.RESULT_OK,outData);
finish();
}
});
}
</p></textarea><p><strong><em>ContactPickerTest.java </em></strong></p>
<textarea readonly name="code" class="java">package com.blueeagle;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;<p>/*</p>
<p>* Android开发之Intent、广播和接收</p>
<p>*</p>
<p>* Created on: 2011-8-15</p>
<p>* Author: blueeagle</p>
<p>* Email: liujiaxiang@gmail.com</p>
<p>*/</p></textarea><textarea readonly name="code" class="java">public class ContactPickerTest extends Activity {
/** Called when the activity is first created. */
public static final int PICK_CONTACT = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.contentpicktester);
Button myButton = (Button)findViewById(R.id.pick_content_button);
myButton.setOnClickListener(new OnClickListener(){
public void onClick(View view){
Intent intent = new Intent(Intent.ACTION_DIAL,Uri.parse("content://contacts/"));
startActivityForResult(intent,PICK_CONTACT);
}
});
}
@Override
public void onActivityResult(int reqCode,int resCode,Intent data){
super.onActivityResult(reqCode, resCode, data);
switch(reqCode){
case(PICK_CONTACT):{
if(resCode == Activity.RESULT_OK){
Uri contactData = data.getData();
Cursor c = managedQuery(contactData,null,null,null,null);
c.moveToFirst();
String name;
name = c.getString(c.getColumnIndexOrThrow(People.NAME));
TextView tv;
tv = (TextView)findViewById(R.id.selected_contact_textView);
tv.setText(name);
}
break;
}
}
}
}
}</textarea><p><br>
Listitemlayout.xml</p>
<textarea readonly name="code" class="html"><?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:id="@+id/itemTextView"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:padding="10px"

android:textSize="16px"

android:textColor="#FFF"

/>

</LinearLayout>

Contentpicktester.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:id="@+id/selected_contact_textView"

/>

<Button

android:id="@+id/pick_content_button"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="Pick Contact"

/>

</LinearLayout>

Main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<ListView

android:id="@+id/contactListView"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

/>

</LinearLayout>
</textarea><p>AndroidManifest.xml</p>
<p></p>
<textarea readonly name="code" class="html"><?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.blueeagle"

android:versionCode="1"

android:versionName="1.0">

<uses-sdk android:minSdkVersion="8" />



<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".ContactPicker"

android:label="@string/app_name">

<intent-filter>

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

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

<data android:path = "contacts"

android:scheme="content"/>

</intent-filter>

</activity>

<activity android:name=".ContactPickerTest"

android:label="Cotent Pick Tester">

<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.READ_CONTACTS"/>

</manifest>
</textarea><p><br></p>
<h3>使用Intent Filter作为插件和扩展</h3>
<p>Android还可以让未来的包对现有的应用程序提供新的功能。并且可以使用IntentFilter在运行时动态地填充菜单。</p>
<p> 这就是所谓的插件模型。这样它们就可以通过新的应用程序组件来充分利用现在还没有实现的功能,而不用修改或者重新编译项目。</p>
<h2>使用Intent 来广播事件</h2>
<p>广播事件处理机制是系统级别的,可以通过构建Intent对象,然后调用sendBroadcast方法将广播发出。事件的接受是通过一个继承自BroadcastReceiver的类来实现的。继承后重写onReceiver()方法,在该方法中相应时间。</p>
<p>Intent可以作为不同进程间传递数据和事件的媒介。</p>
<p>例如:当来电,来信息,网络状态发生变化,电池电量发生变化的时候。Android会将这些信息广播出去。广播的这个过程,就是用Intent的过程。然后,比如我们开发一个监听电池电量变化的应用程序。这个程序注册了针对电池电量变化这一广播的接受。即Broadcast Receiver,那么就可以进行处理,比如接收到电池电量的信息后,以百分比的形式显示出来。</p>
<p>程序主动广播Intent是一个比较简单的过程,只需要构建一个Intent,然后把需要广播的数据写进去,调用sendBroadcast方法进行广播就可以了。</p>
<p>网上对于广播和接收写的例子较多,但是不够彻底。自定义广播事件的DEMO更是难以实现。系统自己的广播比较好解决。如何自定义自己的广播事件呢?</p>
<p>首先,先定义广播:</p>
<p>建立一个工程,作为广播的工程,以后的工程都可以接受这个工程广播的数据。</p>
<p>广播工程代码如下:</p>
<p>MyBroadcast.java</p>
<textarea readonly name="code" class="java">package com.todd;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
<p>/*</p>
<p>* Android开发之Intent、广播和接收</p>
<p>*</p>
<p>* Created on: 2011-8-15</p>
<p>* Author: blueeagle</p>
<p>* Email: liujiaxiang@gmail.com</p>
<p>*/</p>
public class MyBroadcast extends Activity {

public static final String NEW_BROADCAST = "com.todd.NEW_BROADCAST";

/* 这个静态常量字符串可以自己随便定义,代表自定义的action*/

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

Button mybutton = (Button)findViewById(R.id.mybutton);

mybutton.setOnClickListener(new Button.OnClickListener() {

public void onClick(View v) {

Intent myIntent = new Intent(NEW_BROADCAST);

myIntent.putExtra("MSG", "地瓜地瓜,我是土豆!");

myIntent.setAction(NEW_BROADCAST);

sendBroadcast(myIntent);

}

});

}

}</textarea><p>main.xml</p>
<textarea readonly name="code" class="html"><?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<Button

android:id="@+id/mybutton"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="发送广播"

/>

</LinearLayout>
</textarea><p><br></p>
<p>然后再建立一个工程,作为接收的工程,这个工程负责接收广播工程广播出来的数据。</p>
<p>代码如下:</p>
<p>Intent_Receiver.java</p>
<textarea readonly name="code" class="java">package com.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
<p>/*</p>
<p>* Android开发之Intent、广播和接收</p>
<p>*</p>
<p>* Created on: 2011-8-15</p>
<p>* Author: blueeagle</p>
<p>* Email: liujiaxiang@gmail.com</p>
<p>*/</p>
public class Intent_Receiver extends BroadcastReceiver {

/** Called when the activity is first created. */

@Override

public void onReceive(Context context, Intent intent) {

// TODO Auto-generated method stub

String message = intent.getExtras().getString("MSG");

Toast.makeText(context, message, Toast.LENGTH_LONG).show();

System.out.println(message);

}

}
</textarea><p><br>
到这里还不算完。需要有一个注册的过程。注册的过程,就是让接收工程知道我要接收来自哪一个Intent的数据。</p>
<p>在androidmanifest.xml中注册如下:</p>
<textarea readonly name="code" class="html"> <receiver android:name=".Intent_Receiver">

<intent-filter>

<action android:name="com.todd.NEW_BROADCAST" />

</intent-filter>

</receiver>
</textarea><p><br>
这样就把<em>"com.todd.NEW_BROADCAST"</em>动作注册到了接收工程中。如此,接收工程完毕。</p>
<p>但是这样就结束了吗?还没有。如果此时编译后,广播工程没有任何问题,但是接收工程会出错,classcast的错误。这是因为,我们在编译接收工程的时候,没有给接收工程一个Activity用于显示接收的信息。因此,我们需要定义一个Activity.</p>
<p>代码如下:</p>
<p>IntentRes.java</p>
<textarea readonly name="code" class="java">package com.receiver;</textarea><textarea readonly name="code" class="java">import android.app.Activity;
import android.os.Bundle;</textarea><textarea readonly name="code" class="java"><p>/*</p>
<p>* Android开发之Intent、广播和接收</p>
<p>*</p>
<p>* Created on: 2011-8-15</p>
<p>* Author: blueeagle</p>
<p>* Email: liujiaxiang@gmail.com</p>
<p>*/</p>
public class IntentRes extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}

}</textarea><textarea readonly name="code" class="java">当然,在相应的AndroidManifest.xml文件中要修改,写为:</textarea><textarea readonly name="code" class="java"><pre class="html" name="code"></pre></textarea><br>
<activity android:name=".IntentRes" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity><br><pre></pre>
<p>至此,就完成了广播和接收。他们位于不同的工程中。 </p>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值