8、Android中Intent(意图)

来源:互联网 发布:360网络连接配置有问题 编辑:程序博客网 时间:2024/06/04 18:51

AndroidIntent(意图)

Android基本的设计理念是鼓励减少组件间的耦合,因此Android提供了Intent (意图Intent提供了一种通用的消息系统,它允许在你的应用程序与其它的应用程序间传递Intent来执行动作和产生事件。使用Intent可以激活Android应用的三个核心组件:

活动、服务和广播接收器。


Intent可以划分成显式意图和隐式意图。

显式意图:调用Intent.setComponent()Intent.setClass()方法明确指定了组件名的Intent为显式意图,显式意图明确指定了Intent应该传递给哪个组件。

隐式意图:没有明确指定组件名的Intent为隐式意图。 Android系统会根据隐式意图中设置的动作(action)、类别(category)、数据(URI和数据类型)找到最合适的组件来处理这个意图。查找规则请见ppt下方备注。

<intent-filter> 

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

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

<data android:scheme="tel" /> 

</intent-filter> 

<intent-filter> 

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

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

<data android:mimeType="vnd.android.cursor.item/phone" /> 

</intent-filter>




调用Android 专有类Intent 进行架构屏幕之间的切换。Intent 是描述应用想要做什么。Intent 数据结构两个最重要的部分是

1、动作

2、动作对应的数据

典型的动作类型有:

MAIN(活动的门户)

VIEW

PICK

EDIT

而动作对应的数据则以URI 的形式进行表示。

例如:要查看某个人的联系方式,你需要创建一个动作类型为VIEW 的Intent,以及一个表示这个人的URI。


与之有关系的一个类叫IntentFilter。相对于intent 是一个有效的做某事的请求,一个intentfilter 则用于描述一个activity(或者IntentReceiver)能够操作哪些intent。一个activity 如果要显示一个人的联系方式,需要声明一个IntentFilter,这个IntentFilter 要知道怎么去处理VIEW 动作和表示一个人的URI。

IntentFilter 需要在AndroidManifest.xml 中定义。

通过解析各种intent,从一个屏幕导航到另一个屏幕是很简单的。当向前导航时,activity 将会调用startActivity(IntentmyIntent)方法。然后,系统会在所有安装的应用程序中定义的IntentFilter 中查找,找到最匹配myIntent 的Intent 对应的activity。

新的activity 接收到myIntent 的通知后,开始运行。当startActivity 方

法被调用将触发解析myIntent 的动作,这个机制提供了两个关键好处:

A、Activities 能够重复利用从其它组件中以Intent 的形式产生的一个请求;
B、Activities 可以在任何时候被一个具有相同IntentFilter 的新的Activity 取代。


IntentReceiver:
当你希望你的应用能够对一个外部的事件(如当电话呼入时,或者数据网络可用时,或者到了晚上时)做出响应,你可以使用一个IntentReceiver。虽然IntentReceiver 在感兴趣的事件发生时,会使用NotificationManager通知用户,但它并不能生成一个UI。IntentReceiver 在AndroidManifest.xml 中注册,但也可以在代码中使用
Context.registerReceiver()进行注册。当一个intentreceiver 被触发时,你的应用不必对请求调用intentreceiver,
系统会在需要的时候启动你的应用。各种应用还可以通过使用Context.broadcastIntent()将它们自己的intentreceiver 广播给其它应用程序。



一个startActivityForResult 的写法:

Intent intent = new Intent(Main.class,Chatter.class);

EditText edittext = (EditText)findViewById(R.id.EditText01);

CharSequence text = edittext.getText);

intent.put("TEXT",text);

//切换到Chatter ,同时等待响应,设置requestCode, = SHOW_EDITOR 

//( static final int SHOW_EDITOR = 0)

startActivityForResult(intent,SHOW_EDITOR);


protected void onActivityResult(int requestCode,int resultCode,Intent data){

if(requestCode == SHOW_Editor){

if(requestCode==RESULT_OK){

TextView textView = (TextView)findViewById(R.id.TextView02);

textView.setText("Resule_OK:" + data.getCharSquenceExtra("TEXT"));

}

}


}


Chatter.java

Bundle extras = getIntent.getExtras();

if(extras != null){

EditText editText = (EditText)findViewById(R.id.EditText01);

editText.setText(extras.getCharSequence("TEXT"));


}


```

//用setResult()回到Main Acticity 的onActivityResult(),并告知处理响应结果resultCode 是RESULT_OK

//调用finish()结束自己的Chartter Activity 

Intent intent = new Intent();

```

intent.putExtra("TEXT",text);

//响应信息,回到Main resultCode == RESULT_OK

setResult(RESULT_OK,intent);

finish();



使用Intent启动另一个Activity

Intent showNextPage_Intent=new Intent();
showNextPage_Intent.setClass(UsingBundel.this,NextPageActivity.class);
startActivity(showNextPage_Intent);


在多个Activity之间切换时候,注意每个Activity都应在AndroidManifest.xml 中有所声

明定义(如下)

<application android:label="@string/app_name"
android:icon="@drawable/chinazphone">
<activity android:name=".UsingBundel"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".NextPageActivity" android:label="@string/nextpage" ></activity>
</application>


在不同Task中启动Activity

Intent.FLAG_ACTIVITY_NEW_TASK



Intent与Intent filters
Intent:
Android 使用了一个很特别的类别Intent,用来从一个画面跳另一个画面,Intent 是用来描述一个程
序想要做些什么事情。在Intent 的数据结构中有两个很重要的部分,一个是动作(action)及对数据产生
反应(data to act upon)。Action 主要的内容有MAIN(程序的入口点),VIEW,PICK,EDIT 等等。Data
则是用URI 的形式来表示。比如:想要查看一个人的联络数据时,你需要建立一个Intent,它包含了VIEW
的动作(action)及指向该人数据的URI 描述句。
Intent Filter :
当Intent 要求做某件事时,IntentFilter 被用来描述这个Activity 能够做些什么事情。比如一个Activity
要能够显示个人联络数据,你就必需要在intentFilter 说明你要如何处理个人联络数据, 并用
ACTION_VIEW 呈现出来。IntentFilter 都会在AndroidManifest.xml 清单里面声明。

Broadcast Intent Receiver



实例一:利用Intent打电话

Intent DialIntent = new Intent (Intent.DIAL_ACTION,Uri.parse("tel:5551212"));
还可以使用voicemail 来替代tel: 呼出一个电话voice的快捷方式


Intent 创建以后,必须告诉Android在新的活动中被启动,要使用
setLaunchFlags()的Intent方法


可以接受setLaunchFlags()合适参数列表
59
对于你的应用程序,把第一个参数<intent_name>用 DialIntent 替换掉。要
获得第二个参数的数值,请参考 Activity  Action 中的列表。(列表在文章中:
什么是 Intent)。要呼叫拨号盘,你需要使用 DIAL_ACTION  Intent。要正确的呼
叫 Intent,使用 Intent.DIAL_ACTION 这个格式。最后的参数<data>,就是电话
号码。DIAL_ACTION  intent 把号码作为一个 URI。因此,你需要使用 Uri.parse
来分析出电话号码。使用 Uri.parse 将确保 DIAL_ACTION  intent 能够理解你试
图拨打的号码。你传递了一个 Uri.parse 的字符串来展示你要拨打的号码,在本
例中是  "tel:5551212"  。
为你项目创建的最后一个呼叫应该像这样:
提示
你使用记号  tel:<phone_number>来呼叫一个指定的电话号码。你还可以使用
voicemail 来替代 tel:呼出一个电话 voicemail 的快捷方式。
Intent 创建后,你现在必须告诉 Android 你想要拨号盘在新的活动中被启
动。要这样做,你使用 setLaunchFlags()的 Intent 方法。你必须为启动来传递
setLaunchFlags()合适的参数。下面是可以设置接受启动旗帜的一组列表:
注意
在其它情况下,可能会有超过一个的旗帜被设置来完成希望的结果。
●  NO_HISTORY_LAUNCH  启动活动,不记录在系统启动历史中
●  SINGLE_TOP_LAUNCH  告诉系统不要启动活动,如果该活动已经在运行
●  NEW_TASK_LAUNCH  启动活动
●  MULTIPLE_TASK_LAUNCH  启动活动,即使它已经在运行了
●  FORWARD_RESULT_LAUNCH  允许新的活动来接受结果,这个结果通常被转递给
现存的活动。本例中,你要使用 intent.NEW_TASK_LAUNCH,这样可以简单的让
你打开一个新的拨号盘活动示例:
创建拨号盘的最后一步是启动活动。(更精确的说,你告诉 Android 你有一
个作为新任务来启动的拨号盘。最终由 Android 来启动拨号盘活动)。要告诉
Android 你要启动拨号盘,你需要使用 startActivity():
请注意到你把 intent 传递到 startActivity()。这个 Intent 然后传递到
Andriod,然后活动被执行。完整的 AndroidPhoneDialer.java 文件代码应当如
下:
Intent  <intent_name>  =  new  Intent(<Android_Intent>,<data>)
Intent  DialIntent  =  new
Intent(Intent.DIAL_ACTION,Uri.parse("tel:5551212"));
DialIntent.setLaunchFlags(Intent.NEW_TASK_LAUNCH  );
startActivity(DialIntent);
package  android_programmers_guide.AndroidPhoneDialer;import  android.app.Activity;
import  android.content.Intent;
import  android.os.Bundle;
import  android.net.Uri;
public  class  AndroidPhoneDialer  extends  Activity  {
/**  Called  when  the  Activity  is  first  created.  */
@Override
public  void  onCreate(Bundle  icicle)  {
super.onCreate(icicle);
setContentView(R.layout.main);
/**  Create  our  Intent  to  call  the  Dialer  */
/**  Pass  the  Dialer  the  number  5551212  */
Intent  DialIntent  =  new
Intent(Intent.DIAL_ACTION,Uri.parse("tel:5551212"));
/**    Use    NEW_TASK_LAUNCH    to    launch    the    Dialer
Activity  */
DialIntent.setLaunchFlags(Intent.NEW_TASK_LAUNCH  );
/**  Finally  start  the  Activity  */
startActivity(DialIntent);
}
}

你真正需要的是 CALL_ACTION。
很多的时候 DIAL_ACTION 打开 Andriod拨号盘,
CALL_ACTION 将会启动电话的呼叫过程并且开始呼叫提供的号码


61
动代码中的哪一个地方增加选择的 Intent。另外,你将学习如何分析一个作为
URI 的电话号码。从拨号盘活动代码变成呼叫活动你需要更改一些代码。在本节
中,你回去编辑 AndroidPhoneDialer 活动,在打开拨号盘后,来打一个电话。
在活动中增加一个 Intent,你还是需要 Intent 和 Uri 包装,所以,在
AndroidPhoneDialer.java 的文件头部保留这一部分。
这些包装将确保你不仅需要 intent 而且同样会传递需要的电话号码数据到
Intent 中(用 Uri 包装)。
提示
如果你不按照顺序匆匆看完这个章节,而且没有运作前一节实际的项目,那么就
简单的创建一个新的项目,命名为 AndroidPhoneDialer,然后增加前面提到的
两个包装进去。这样会赶上进度。
现 在 看 看 在 本 章 早 些 时 候 表 格 7-1  中 可 以 使 用 的 Activity  Action
Intents。你真正需要的是 CALL_ACTION。很多的时候 DIAL_ACTION 打开 Andriod
拨号盘,CALL_ACTION 将会启动电话的呼叫过程并且开始呼叫提供的号码。
要创建 Intent,使用和创建拨号盘同样的程序,只是这次使用 CALL_ACTION:
请注意你使用 Uri.parse 来传递一个正确的电话号码到活动中。下一步是告诉
Android 你要把这个活动设为启动,并且启动它。使用下面的两行代码来实现:
在第一行,你发送启动旗帜到 NEW_TASK_LAUNCH。这个会启动一个呼叫的新
示例。最后,你告诉 Android 使用你的 Intent 启动活动。当结束时,你的
AndroidPhoneDialer.java 文件应当如下:
import  android.content.Intent;
import  android.net.Uri;
Intent  CallIntent  =  new
Intent(Intent.CALL_ACTION,Uri.parse("tel:5551212"));
CallIntent.setLaunchFlags(Intent.NEW_TASK_LAUNCH  );
startActivity(CallIntent);
package  android_programmers_guide.AndroidPhoneDialer;
import  android.app.Activity;
Chapter  7:  Using  Intents  and  the  Phone  Dialer  129
import  android.content.Intent;
import  android.os.Bundle;
import  android.net.Uri;
public  class  AndroidPhoneDialer  extends  Activity  {
/**  Called  when  the  Activity  is  first  created.  */
@Override
public  void  onCreate(Bundle  icicle)  {
super.onCreate(icicle);62
编译这个应用程序并且观察结果,你应当看到如下类似的错误信息。我实际上有
意的要你看看这个错误,因为它展示了我们还没有发现的 Android 的另一面,错
误的文本如下:
Android 通过要求许可被执行来准许恰当的行动,在下一节叙述。
编辑活动许可
编辑活动许可  第七章(5)  (5)  (5)  (5)
大多数的 Activity  Action  Intents 是在需要许可在 Android 允许它行动之
前的目录内的。和大多数的系统一样,Android 只是需要确保有资格的活动来执
行在它们之外的活动。这儿是许可可以使用的活动:
setContentView(R.layout.main);
/**   Create   our   Intent   to   call   the   device's   Call
Activity  */
/**  Pass  the  Call  the  number  5551212  */
Intent  CallIntent  =  new
Intent(Intent.CALL_ACTION,Uri.parse("tel:5551212"));
/**  Use  NEW_TASK_LAUNCH  to  launch  the  Call  Activity
*/
CallIntent.setLaunchFlags(Intent.NEW_TASK_LAUNCH  );
/**  Finally  start  the  Activity  */
startActivity(CallIntent);
}
}
Application_Error:

Java.lang.SecurityException:
Permission  Denial:  starting  Intent

●  ACCESS_ASSISTED_GPS       
●  INTERNAL_SYSTEM_WINDOW
●  ACCESS_CELL_ID 
·RAISED_THREAD_PRIORITY
●  ACCESS_GPS 
●  READ_CONTACTS
●  ACCESS_LOCATION 
●  READ_FRAME_BUFFER
●  ACCESS_SURFACE_FLINGER ●
RECEIVE_BOOT_COMPLETED
●  ADD_SYSTEM_SERVICE        
 ●  RECEIVE_SMS
●BROADCAST_PACKAGE_REMOVED
●  RECEIVE_WAP_PUSH
●  BROADCAST_STICKY ●  RUN_INSTRUMENTATION
●  CALL_PHONE ●  SET_ACTIVITY_WATCHER
●CHANGE_COMPONENT_ENABLED_STATE
●  SET_PREFERRED_APPLICATIONS
●  DELETE_PACKAGES ●  SIGNAL_PERSISTENT_PROCESSES
●  DUMP ●  SYSTEM_ALERT_WINDOW
●  FOTA_UPDATE ●  WRITE_CONTACTS
●  GET_TASKS ●  WRITE_SETTINGS
●  INSTALL_PACKAGES

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





一个带有号码验证的打电话程序


72
EditText  View 中,并且发送到 Call 活动中。这个真不是最佳的应用程序开发。
研究一下并且增加验证到 EditText 中。使用下面的参数来修改项目:
●   使 用 常 规 的 表 达 式 来 验 证 一 个 号 码 被 输 入 到 EditText 中 (package
java.regex)。
●  使用 showAlert(  )  语法来显示一条信息告诉用户他们输入的内容和你的常
规表达式不匹配。当你觉得已经找到解决方案,和下面的代码做个比较:
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"
>
<TextView  android:id="@+id/textLabel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter  Number  to  Dial:"
/>
<EditText  android:id="@+id/phoneNumber"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button  android:id="@+id/callButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Show  Dialer"  />
</LinearLayout>
AndroidPhoneDialer.java
package  android_programmers_guide.AndroidPhoneDialer;
import  android.app.Activity;
import  android.os.Bundle;
import  android.widget.Button;
import  android.view.View;
import  android.content.Intent;
import  android.net.Uri;
import  android.widget.EditText;
import  java.util.regex.*;
public  class  AndroidPhoneDialer  extends  Activity  {
/**  Called  when  the  activity  is  first  created.  */
@Override
public  void  onCreate(Bundle  icicle)  {super.onCreate(icicle);
setContentView(R.layout.main  );
final  EditText  phoneNumber  =  (EditText)
findViewById(R.id.phoneNumber  );
final Button callButton = (Button)
findViewById(R.id.callButton);
callButton.setOnClickListener(new
Button.OnClickListener()  {
Chapter  7:  Using  Intents  and  the  Phone  Dialer  147
public  void  onClick(View  v){
if
(validatePhoneNumber(phoneNumber.getText().toString())){
Intent  CallIntent  =  new
Intent(Intent.CALL_ACTION,Uri.parse("tel:" +
phoneNumber.getText()));
CallIntent.setLaunchFlags(Intent.NEW_TASK_LAUNCH  );
startActivity(CallIntent);
}
else{
showAlert("Please  enter  a  phone  number  in  the  X-XXX-XXX-
XXXX
format.",0,  "Format  Error",  "Re-enter  Number",false);
}
}
});
}
public  boolean  validatePhoneNumber(String  number){
Pattern phoneNumber =
Pattern.compile("(\\d-)?(\\d{3}-)?\\d{3}
\\d{4}");
Matcher  matcher  =  phoneNumber.matcher(number);
return  matcher.matches();
}
}






android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity

Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

Context中有一个startActivity方法,Activity继承自Context,重载了startActivity方法。如果使用 Activity的startActivity方法,不会有任何限制,而如果使用Context的startActivity方法的话,就需要开启一个新的task,遇到上面那个异常的,都是因为使用了Context的startActivity方法。解决办法是,加一个flag。

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 

以上转自:http://www.cnblogs.com/rioder/archive/2011/11/02/2233584.html

以下为Context源码中的startActivity:

    /**
     * Launch a new activity.  You will not receive any information about when
     * the activity exits.
     *
     * <p>Note that if this method is being called from outside of an
     * {@link android.app.Activity} Context, then the Intent must include
     * the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag.  This is because,
     * without being started from an existing Activity, there is no existing
     * task in which to place the new activity and thus it needs to be placed
     * in its own separate task.
     *
     * <p>This method throws {@link ActivityNotFoundException}
     * if there was no Activity found to run the given Intent.
     *
     * @param intent The description of the activity to start.
     *
     * @throws ActivityNotFoundException
     *
     * @see PackageManager#resolveActivity
     */
    public abstract void startActivity(Intent intent);

以上解释了为什么使用Context的startActivity方法(比如在Service中或者BroadcastReceiver中启动Activity)为什么需要添加flag:FLAG_ACTIVITY_NEW_TASK




今天在service中启动startActivity()方法的时候,碰到了如下的异常:

Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

    原来:Context中有一个startActivity方法,Activity继承自Context,重载了startActivity方法。如果使用Activity的startActivity方法,不会有任何限制,而如果使用Context的startActivity方法的话,就需要开启一个新的task,遇到上面那个异常的,都是因为使用了Context的startActivity方法。解决办法是,加一个flag。

   解决方法intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

  这样就可以在新的task里面启动这个Activity了。


原创粉丝点击