传送门☞轮子的专栏☞转载请注明☞http://blog.csdn.net/leverage_1229

一个Android应用程序通常有几个activities。每个act显示一个用户接口允许用户执行一个指定的任务。用户从一个act到另一个act,你的App必须使用一个Intent对象来定义你App想做些什么事。当你通过一个Intent调用startActivity()方法时,系统会使用Intent来鉴定和启动合适的App组件。一个Intent可以明确的启动一个特定的组件(如一个特定的act实例)或隐式启动任何可以处理预定动作的组件,本章我们将讲述怎么使用Intent来执行与其他Apps的一些交互,例如启动另一个App,从那个App接收结果。并使你的应用程序能够响应来自其他App的intents。

1发送用户到另一个App

Android最重要的一个特性之一就是发送用户到另一个App并基于“动作”来执行它的能力。例如,如果你的app有商业地址想要显示在地图上,你不得不在你的App中新建一个activity来显示地图。其实更好的办法是使用Intent发送一个查看地图的外部请求。Android系统会启动那个能查看地址的App。通常,我们使用一个明确的Intent,它定义的明确的类名。然而,当你想有一个单独的应用程序执行时,如“查看地图”,你必须使用一个隐式的Intent。本节讲述如何为一个特定的动作创建隐含的意图,以及怎样用它来启动执行另一个应用程序中的Activity。

1.1构建一个隐式的Intent

隐式intents不用申明启动组件的类名,但需要申明执行的动作。动作指定你想要做的事情,如view(查看),edit(编辑),send(发送)或获得某事物。Intents经常包托一些与动作相关联的税局,如你想要查看的地址,或者你想要发送的email信息。这取决于你想要创建的Intent所发送的数据,数据可能是一个Uri或intent根本不需要数据也能发送。
使用Uri数据拨打电话:

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

当你的app通过startActivity()调用intent时,电话app根据给定的电话号码发起呼叫。
查看一个地图:

// 基于地址的地图点
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// 或基于经纬度的地图点
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z参数表示缩放级别
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

查看一个web页面:

Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

其他种类的隐式intents需要”extra”数据来提供不同的数据类型,如一个字符串。你能使用putExtra()方法来添加一个或更多extra 数据。默认的,系统通过基于Uri的intent来确定适当的MIME(Multipurpose Internet Mail Extensions)类型。如果你在intent中不包含一个Uri,你应该使用setType()来指定intent相关联的数据类型。设置MIME类型来进一步指定activities将要接收的intent类型。
发送带有附件的电子邮件:

Intent emailIntent = new Intent(Intent.ACTION_SEND);
//没有Uri的intent,所以需要声明”text/plain”的MIME类型
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // 收件人
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));

创建一个日历事件:

Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);
Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");

注意: 对于日历事件的intent只在API Level或更高版本下才支持。

1.2验证一个App接收的Intent

我们总是应该在调用一个intent之前先包含一个验证。这是一个好的习惯,因为如果你在app中调用intent后,如果没有可用的设备,那么你的app会崩溃.为了验证那个activity可用,我们可以调用queryIntentActivities()来获得一个list,如果返回的List不为空,那么你能安全的使用intent。

PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;

如isIntentSafe为true,那么表示至少有一个app能响应我们的intent。如果false,表示没有一个app能处理这个intent。

1.3使用Intent启动一个Activity

你可以创建intent并设置extra的信息,然后调用startActivity()。如果系统识别有多个activity能处理这个intent,那么它会显示一个对话框让你自主选择。如果只有一个activity的话,系统会立即启动这个activity。

让我们看看如下的代码,看它是怎么启动activity的:

// 构建intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
// 验证上面的mapIntent
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;
// 如果它是安全的就启动这个activity
if (isIntentSafe) {startActivity(mapIntent);
}

1.4显示APP选择器

注意当你通过intent使用startActivity()启动activity时,如果有多个app响应,如果多个应用可以处理我们的操作,并且用户可能想要每次启动不同的app,比如一个”分享”的动作,分享的渠道可能有多个app组成,这样用户每次可能使用不同的app。那么我们可以使用createChooser()来创建显示选择器。

Intent intent = new Intent(Intent.ACTION_SEND);
...
// 用于标题的文本资源例如"Share this photo with"
String title = getResources().getText(R.string.chooser_title);
// 创建并启动chooser
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);

2从Activity获得结果

启动另一个activity并不一定是单向的。我们还可以启动另一个activity,并接收返回结果.。如果需要接收返回结果,我们可以使用startActivityForResult()。L例如。你的应用启动一个摄像机app并接收拍摄照片的结果。当然,获得响应的activity必须被设计为返回一个结果,当它这么做时,它发送一个intent对象的结果。你的activity在onActivityResult()回调方法中会接收到这个intent。虽然我们可以使用明确的和隐式的intent,但这里实际建议你应该使用一个明确的intent,以确保收到了预期的结果。

2.1启动Activity

使用startActivityForResult()方法,需要传递一个额外的int参数。Int参数的意思为”request code”,就是标识一个请求。当收到intent结果时,回调提供了相同的请求的代码,使应用程序可以正确识别结果,并决定如何处理它。
如何启动一个activity并允许用户选择一个联系人:

static final int PICK_CONTACT_REQUEST = 1;  // request code
...
private void pickContact() {Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));pickContactIntent.setType(Phone.CONTENT_TYPE); startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}

2.2接收一个结果

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {// 检查响应的请求if (requestCode == PICK_CONTACT_REQUEST) {// 确保请求是成功的if (resultCode == RESULT_OK) {// Do something...}}
}

为了成功地处理结果,你必须明白,intent结果的格式将是什么。例如,People app(早些版本叫Contacts app)始终用content URI返回结果并识别被选择的联系人,Camera app在返回一个Bitmap。
将上面的代码扩展一下,让我们看下怎样读取联系人数据:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {//检查响应的请求if (requestCode == PICK_CONTACT_REQUEST) {//确保请求是成功的if (resultCode == RESULT_OK) {// 获得指向选定联系人的URIUri contactUri = data.getData();//我们只需要号码(NUMBER)列 String[] projection = {Phone.NUMBER};// 在联系人中执行查询,获得NUMBER column// 我们不需要挑选或排序// 提示:  query()方法应该在单独的线程执行,避免阻塞UI线程// 考虑使用CursorLoader 执行查询Cursor cursor = getContentResolver().query(contactUri, projection, null, null, null);cursor.moveToFirst();// 从NUMBER column中检索电话号码int column = cursor.getColumnIndex(Phone.NUMBER);String number = cursor.getString(column);// 使用电话号码做些事情}}
}

注意:Android 2.3 (API level 9)以前,在Contacts Provider执行一个查询需要申明READ_CONTACTS权限,虽然在2.3开始有一个临时的权限可以让你去读取Contacts Provider,但依旧不能查询。所以不管什么版本我们都申明READ_CONTACTS权限即可。

3允许其他Apps启动你的Activity

在android平台上,如果你要集成facebook的社交功能,那么你可以使用facebokk提供的一个apk,里面集成了facebook的众多功能,如分享信息照片等。在实际开发过程中,可能我们需要开发这样的一个类似的apk,别担心,android提供这样的功能并且很容易实现。

3.1添加一个Intent Filter

我们需要正确的定义intents,让activity能更好的处理。每一个intent filter应该添加具体的action类型和数据类型。系统可能会发送一个给定的intent到一个activity,如果activity有一个intent filter并符合下列条件的intent对象:
Action
一个用来执行动作的字符串名字。例如ACTION_SEND或ACTION_VIEW。在intent filter中的<action>节点指定它。必须是全称,不能使用API常量。
Data
相关的intent中数据的描述。在intent filter中的<data>节点指定它。在这个节点中使用一个或多个属性,你能指定MIME类型,一个URI前缀,一个URI组合,或者是以上内容的组合。如果你不需要申明指定的Uri数据,那你仅指定 android:mimeType属性即可,例如text/plain或image/jpeg。
Category
提供一种额外的方法来表示activity处理的intent,通常与用户手势和开始位置相关。系统支持几种不同的类别,但大部分都很少使用,一般在intent filter中的<category>节点使用CATEGORY_DEFAULT。
下面的<intent-filter>中定义的内容表示在处理ACTION_SEND的intent中使用的数据类型为文本或图像。

<activity android:name="ShareActivity"><intent-filter><action android:name="android.intent.action.SEND"/><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="text/plain"/><data android:mimeType="image/*"/></intent-filter>
</activity>

每一个传入的intent只有一个动作和一种数据类型,但声明多个<data>,<action>,<category>也是OK的,如果动作和数据类型相互排斥的话,你就应该分开它们。加入你的activity处理文本和图像,并且使用ACTION_SEND和ACTION_SENDTO intents。这样就是错误的,在这种情况下你应该使用两个<intent-filter>来分开它们。因为SENDTO必须使用Uri数据,并且需要sms和smsto的scheme。

<activity android:name="ShareActivity"><!—为发送文本过滤; 接收SENDTO action 使用 sms URI schemes --><intent-filter><action android:name="android.intent.action.SENDTO"/><category android:name="android.intent.category.DEFAULT"/><data android:scheme="sms" /><data android:scheme="smsto" /></intent-filter><!—为发送文本或图像过滤; 接收SEND action和文本或者图像数据 --><intent-filter><action android:name="android.intent.action.SEND"/><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="image/*"/><data android:mimeType="text/plain"/></intent-filter>
</activity>

为了接收隐式的intents,我们必须在<intent-filter>中定义CATEGORY_DEFAULT中,如果没声明,那么你的activity不能解决处理隐式的intents。

3.2 在Activity中处理intent

为了决定在你activity中想要处理的动作,你能在启动activity时读取intent。在启动activity时,调用getIntent()方法来检索启动activity的intent。你能在任意时刻这么做,但最好在onCreate()或onStart()中这样做。

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);//获得启动activity的intentIntent intent = getIntent();Uri data = intent.getData();// 解决intent类型想做什么if (intent.getType().indexOf("image/") != -1) {//处理图像数据} else if (intent.getType().equals("text/plain")) {// 处理文本}
}

3.3 返回一个结果

如果你想要返回一个结果到你调用的activity,最简单的就是调用setResult()方法来指定结果代码和intent结果。当你的操作完成时,用户如果想要返回到最开始的activity,调用finish()来关闭和destroy你的activity即可。

// 创建intent来传递某种结果数据
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();

我们可以只指定result code。通常是RESULT_OK或RESULT_CANCELED。你可以添加额外的intent或者不添加。默认的result code是RESULT_CANCELED。所以如果用户在你设置result之前执行Back键,那么最初的activity收到的就是RESULT_CANCELED,这并不是我们预计的结果,这个细节请注意。

让你的Android应用与外部元素互动起来相关推荐

  1. 【错误记录】NDK 导入外部 so 动态库报错 ( java.lang.UnsatisfiedLinkError | Android Studio 配置外部 so 动态库两种方法 )

    文章目录 一.报错信息 二.解决方案 ( Android Studio 配置外部 so 动态库两种方法 ) 1.jniLibs 目录存放 2.libs 目录存放 一.报错信息 外部引用 so 动态库 ...

  2. android 文件公有存储,如何将文件写入Android中的外部公共存储,以便从Windows中看到它们?...

    如何将文件写入Android中的外部公共存储,以便从Windows中看到它们? 我的应用程序应该将文件保存到一个地方,当您将手机/平板电脑连接到计算机时,您可以通过系统文件资源管理器看到它们. 这就是 ...

  3. android放在上个元素的左边代码,控件悬浮在某个控件之上 Android五大布局方式——相对布局(RelativeLayout)属性详解...

    如图所示,想要实现搜索框在轮播图上面,不管滑动与否,这个组合控件都在上面 1.就要用到RelativeLayout,相对于父元素定位,而且这个搜索框的组合控件必须要放在所有控件下面,在使用androi ...

  4. Android 遍历 View 中子元素

    Android 遍历 View 中子元素 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 ...

  5. android设置自定义按钮,Android自定义View之元素按钮

    Android自定义View之元素按钮 之前在dribbble看到的三个元素的按钮,参考了设计的创意,添加了自己定义的动画效果来实现.先看效果 效果图 分别是水火电三个元素的按钮实现.其中电的实现最简 ...

  6. android同服务器端互动,一种基于Android平台的多屏互动系统设计

    多屏互动是指各种不同智能设备可以互相将多媒体资源推送到屏幕中并且播放的技术.局域网智能设备可以实现资源的互通互联和共享,同时也可以扩大局域网的智能设备到广域网中,实现三网融合方案,并能实现互通互联在网 ...

  7. 基于Android的中小学家校互动平台的设计与实现

    基于Android的中小学家校互动平台的设计与实现 摘 要 如今,互联网发展越来越快,手机应用开发技术日渐完善.随着社会信息化水平的提高,以及对新一代教育的日益关注,家校之间的沟通.家校互动的重要性日 ...

  8. 【Android 逆向】Android 系统文件分析 ( 外部存储设备文件 | sbin 命令程序目录 | dev 字符设备目录 )

    文章目录 一.外部存储设备文件 二.sbin 命令程序目录 三.dev 字符设备目录 一.外部存储设备文件 /sdcard 文件是一个链接 , 相当于快捷方式 , 其实际的目录是 /storage/s ...

  9. android 存储无法写入,在Android中的外部存储中写入文件

    我想在外部存储sdCard中创建一个文件并写入它.我已经通过互联网搜索并尝试但没有得到结果,我已经在Android Manifest文件中添加了权限,我在模拟器上这样做,我正在尝试下面的代码和获取ER ...

最新文章

  1. 再见中台,你好!企业数字化转型
  2. 2014025679 《嵌入式系统程序设计》第五周学习总结
  3. python 定义变量x格式_如何从CSV文件中提取数据列并将它们定义为x和y变量,然后使用pylab在python中绘制它们?...
  4. 多目标跟踪(MOT)领域近期值得读的几篇论文
  5. can3--socketcan之mcp251x.c
  6. 数据结构与算法 | 堆
  7. P4248 [AHOI2013]差异
  8. VOIP,PSTN,ISDN
  9. 《简明电路分析》——导读
  10. php 访问url获得返回值,如何在curl php请求中获取数组值作为返回值?
  11. YARN组件详细介绍
  12. python遇到‘\u’开头的unicode编码
  13. 阶段5 3.微服务项目【学成在线】_day01 搭建环境 CMS服务端开发_13-MongoDb入门-数据库和集合...
  14. python之struct详解_Python struct模块解析
  15. cv2.error: OpenCV(4.5.3) C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-q3d_8t8e\opencv\modul
  16. 如何阅读《如何阅读一本书》?
  17. 标准盒模型和怪异盒模型小结
  18. 一键服务端是什么意思_音视频混流是什么意思?混流的优势和劣势
  19. Java中利用freemarker导出word表格并合并单元格
  20. 访达前往文件夹_(苹果电脑excle没有查找全部)苹果笔记本有没有自带excel

热门文章

  1. DSP sawtooth锯齿波与square方波matlab产生(M2.2)
  2. db2判断字符为空_算法之字符串转换为数字
  3. mybatisplus service insert 空指针_c++ 图解层序遍历和逐层打印智能指针建造的二叉树...
  4. mysql表 spid program_SQL Server 表,记录 死锁解决办法
  5. html京东快报,练习3:仿京东快报.html
  6. 学计算机的基本技能,大学计算机基础—基本应用技能[规整].pdf
  7. git21天打卡day15-添加提交修改文件
  8. conda h5py_修改conda安装路径
  9. php加密数据库工具,各位用php将密码存入数据库,都用什么方法进行加密的?
  10. 审车按月还是日期_大额存单,应该选择按月付息还是到期一次性还本付息?