AndroidIntent(意图)

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

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


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

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

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

<intent-filter>

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

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

<dataandroid:scheme="tel"/>

</intent-filter>

<intent-filter>

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

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

<dataandroid: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了。


更多相关文章

  1. 实战技巧:Android异步指南
  2. 滴滴Android实习生培养计划
  3. Android学习路线总结,绝对干货
  4. android sqlite用管理工具查看
  5. android sqlite用管理工具查看
  6. Android(安卓)adb的使用略解
  7. 箭头函数的基础使用
  8. NPM 和webpack 的基础使用
  9. Python list sort方法的具体使用

随机推荐

  1. 兄弟连学Python__GitHub入门
  2. Python演讲笔记1
  3. 更简单的方法来启用详细日志记录
  4. python 的多线程 调用input后 别的线程也
  5. windows下安装python的三方模块pyExceler
  6. nova中periodic task的实现
  7. python爬网上图片
  8. python xml.sax没有解析器找到py2exe
  9. 获取指定日期的后(前)一(n)天(转)
  10. Python 正则表达式(5)电话号匹配