• 第 21 章 隐式 intent


    请参考教材,全面理解和完成本章节内容... ...复制工程ch20,将工程目录改名为ch21。

    同显式Intent一样,在Android系统中,使用隐式intent可以启动其他应用,比如微信、QQ、浏览器等,但隐式Intent的启动方式比较含蓄,它并不明确指出启动哪一个Activity,仅隐式Intent中指定要完成任务的信息,然后交由系统去分析这个隐式Intent,并帮我们找出能匹配任务的Activity去启动。

    比如,你的应用程序中需要打开一个网页,这时你没有必要自己去实现一个浏览器,只需要调用系统的浏览器来打开网页就行了。使用隐式Intent完成这个任务的代码如下所示:

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse("http://www.baidu.com"));
    startActivity(intent);

    在”陋习手记”应用中,将使用隐式intent实现从联系人列表中选取有此Crime的「嫌疑人」,然后发送「陋习报告」给他。实际使用时,用户从设备上安装的联系人应用中选取联系人,然后再从系统提供的多种“信息发送应用“中,选取一个应用将报告发送出去。 

    image

    图21-1 打开联系人和消息发送应用

    从开发者角度来看,使用隐式intent利用其他应用完成任务,远比自己编写代码从头实现要容易得多。从用户角度来看,他们也乐意在当前应用中协同使用自己熟悉或喜爱的应用。

    创建使用隐式intent前,需先在「陋习手记」应用中完成以下准备工作:

    · 在CrimeFragment的布局上添加Choose Suspect和Send Crime Report按钮;

    · 在Crime类中添加保存「嫌疑人」姓名的mSuspect变量;

    · 使用格式化的字符串资源创建陋习报告模板。

    21.1 添加按钮组件

    首先,我们需要在CrimeFragment布局中添加两个投诉用按钮。添加按钮前,先来添加显示在按钮上的字符串资源,如代码清单21-1所示。

    代码清单21-1 为按钮添加字符串(strings.xml)

        <string name="take">取证!</string>
        <string name="crime_suspect_text">选择嫌疑人</string>
        <string name="crime_report_text">发送陋习报告</string>
    </resources>

    然后,分别在layoutlayout-land目的fragment_crime.xml布局文件中,参照图21-2,添加两个按钮组件。注意,在布局定义示意图中,为集中注意力在新增组件的内容定义上,我们隐藏了第一个线形布局及其全部子元素。

    image

    图21-2 添加嫌疑人选取和陋习报告发送按钮

    在水平模式布局中,需要将新增按钮作为子元素添加到一个新的水平线性布局中,并放在包含日期按钮和“Solved?”单选框的线性布局下方。

    如图21-3所示,在比较小的设备屏幕上,新添加的按钮无法完整的显示。为解决这个问题,需要将整个布局定义放在一个ScrollView中。

    image

    图21-3 水平模式下,新增按钮没有完全显示

    图21-4展示了更新后的布局定义。现在,因为ScrollView是整个布局的根元素,记得不要忘了将命名空间定义从原来的根元素移至ScrollView根元素。

    image

    图21-4 添加嫌疑人选取和陋习报告发送按钮

    现在,可以预览和直接运行「陋习手记」应用,确认新增加的按钮是否显示正常。

    21.2 添加嫌疑人信息至模型层

    接下来,返回到Crime.java中,新增JSON常量以及存储「嫌疑人」姓名的mSuspect成员变量各一个。然后修改JSON方法,将嫌疑人信息序列化为JSON格式(以及从JSON格式还原嫌疑人信息)并添加相应的存取方法,如代码清单21-2所示。

    代码清单21-2 添加嫌疑人成员变量(Crime.java)

    image

    21.3 使用格式化字符串

    最后一项准备任务是创建可填充的「陋习报告」模板。应用运行前,我们无法获知具体陋习细节。因此,必须使用带有占位符(可在应用运行时替换)的格式化字符串。下面是将要使用的格式化字符串:

    <string name="crime_report">%1$s! The crime was discovered on %2$s. %3$s, and %4$s

    %1$s、%2$s等特殊字符串即为占位符,它们接受字符串参数。在代码中,我们将调用getString(...)方法,并传入格式化字符串资源ID以及四个其他字符串参数(与要替换的占位符顺序一致),如下所示:

    String report = getString(R.string.crime_report, mCrime.getTitle(), dateString, solvedString, suspect);

    首先,在strings.xml中,添加代码清单21-3所示的字符串资源。(注:此时字符串资源不能用中文,否则点击「发送陋习报告」按钮是出现异常。)

    代码清单21-3 添加字符串资源(strings.xml)

    image

    然后,在CrimeFragment.java中,添加getCrimeReport()方法创建四段字符串信息,并返回拼接完整的陋习报告文本信息,如代码清单21-4所示。

    代码清单21-4 新增getCrimeReport()方法(CrimeFragment.java)

    image

    至此,准备工作全部完成了,接下来学习如何使用隐式intent。

    21.4 使用隐式 intent

    不论使用隐式还是显示的 Intent,都需要向操作系统描述需要处理的任务。使用显式intent,我们需明确地告诉操作系统要启动的activity类名。下面是之前创建过的显式intent:

    Intent i = new Intent(getActivity(), CrimeCameraActivity.class);
    startActivity(i);

    而使用隐式 intent,只需向操作系统描述清楚我们的工作意图。操作系统会去启动那些对外宣称能够胜任工作任务的activity。如果操作系统找到多个符合的activity,用户将会看到一个可选应用列表,然后就看用户如何选择了。

    21.4.1 隐式intent的组成

    一个隐式的intent由多个部分组成,我们使用它们来定义工作任务,下面是两种不同隐式intent定义:

    // 发送信息Implicit intent
    Intent i = new Intent(Intent.ACTION_SEND);
    i.setType("text/plain");
    i.putExtra(Intent.EXTRA_TEXT, someData);
    startActivity(i);

    // 访问网页Implicit intent
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse("http://www.baidu.com"));
    startActivity(intent);

    各主要的部分的含义如下:。

    • 要执行的操作:通常以Intent类中的常量来表示,如访问某个网页,须使用Intent.ACTION_VIEW;要发送邮件,可使用Intent.ACTION_SEND
    • 要访问数据的位置:可能是设备以外的资源,如某个网页的URL(网址),也可能是指向某个文件的URI(Uniform Resource Identifier, 简称"URI")。
    • 操作涉及数据的类型:指的是MIME形式的数据类型,如text/plaintext/htmlaudio/mpeg3等。如果一个intent包含某类数据的位置,那么通常可以从中推测出数据的类型。

    注:MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。

    是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。如声音、视频和图像等

    注:URI类似一个资源的地址

    Web上可用的每种资源, HTML文档、图像、视频片段、程序等 都由一个通用资源标识符(Uniform Resource Identifier, 简称"URI")进行定位。如https://www.baidu.com/img/bdlogo.png代表下面的图片:

          image

    4. 可选类别

    如果操作用于描述具体要做什么,那么类别通常用来描述我们是何时何地或者说如何使用某个activity的。Android的android.intent.category.LAUNCHER类别表明,activity应该显示在顶级应用启动器中。而android.intent.category.INFO类别表明,虽然activity向用户显示了包信息,但它不应该显示在启动器中。

    一个用来查看某个网址的简单隐式intent会包括一个Intent.ACTION_VIEW操作,以及某个具体URL网址的uri数据。

    基于以上信息,操作系统将启动一个适用的APP及其对应activity(如微信里的发送信息的Activity)。如果有多个适用的APP可选,用户可自行如何选择。如图21-4-1

    image

    图21-4-1 多个适用应用可选,用户可自行选择

    通过对配置文件中的intent过滤器设置,一个activity会对外宣称自己是一个适合处理ACTION_VIEW的activity。例如,如果你要开发一款浏览器应用,为响应ACTION_VIEW操作,你需要在activity声明中包含以下intent过滤器:

    <activity
      android:name=".BrowserActivity"
      android:label="@string/app_name" >
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="http" android:host="www.bignerdranch.com" />
      </intent-filter>
    </activity>

    DEFAULT类别必须明确地在intent过滤器中进行设置。intent过滤器中的action元素告诉操作系统,activity能够处理指定的任务. DEFAULT类别告诉操作系统,activity愿意处理某项任务。DEFAULT类别实际隐含添加到了几乎每一个隐式intent中。(唯一的例外是LAUNCHER类别。)

    如同显式intent,隐式intent也可以包含extra信息。不过,操作系统在寻找适用的activity时,它不会使用任何附加在隐式intent上的extra。

    注意,隐式intent的操作和数据部分也可以与显式intent联合起来使用。这相当于要求特定activity去处理特定任务。

    21.4.2 发送陋习报告

    在「陋习手记」应用中,通过创建一个发送陋习报告的隐式intent,我们来看看隐式intent是如何工作的。陋习报告是由字符串组成的文本信息,我们的任务是发送一段文字信息,因此,隐式intent的操作是ACTION_SEND。它不指向任何数据,也不包含任何类别,但会指定数据类型为text/plain

    text/html & text/plain的区别?

    需要了解的概念

    Content-Type:用于定义用户的浏览器或相关设备如何显示将要加载的数据,或者如何处理将要加载的数据

    MIME:MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

    text/html的意思是将文件的content-type设置为text/html的形式,浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。

    text/plain的意思是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理。

    CrimeFragment.onCreateView(...)方法中,首先以资源ID引用「发送陋习报告」按钮并为其设置一个监听器。然后在监听器接口实现中,创建一个隐式intent并传入startActivity(Intent)方法,如代码清单21-5所示。

    代码清单21-5 发送陋习报告(CrimeFragment.java)

    image

    以上代码使用了一个接受字符串参数的Intent构造方法,我们传入的是一个定义操作的常量。取决于要创建的隐式intent类别,也可以使用一些其他形式的构造方法。其他全部intent构造方法及其使用说明,可以查阅Intent参考文档。因为没有接受数据类型的构造方法可用,所以必须专门设置它。

    报告文本以及报告主题字符串是作为extra附加到intent上的。注意,这些extra信息使用了Intent类中定义的常量。因此,任何响应该intent的activity都知道这些常量,自然也知道如何使用它们关联的值。

    运行「陋习手记」APP并点击「发送陋习报告」按钮。因为刚创建的intent会匹配设备上的许多activity,我们可能看到一个候选activity列表,类似图21-5所示。

    image

    图21-5 愿意发送陋习报告的全部activity

    从列表中作出选择后,可以看到,陋习报告信息都加载到了所选应用中,接下来,只需填入地址,点击发送即可。

    然而,有时我们可能看不到候选activity列表。出现这种情况通常有两个原因,要么是针对某个隐式intent设置了默认响应应用,要么是设备上只有唯一一个activity可以响应隐式intent。

    通常,对于某项操作,最好使用用户的默认应用。不过,在「陋习手记」中,针对ACTION_SEND操作,应该总是将选择权交给用户。要知道,也许今天用户想低调处理问题,只采取邮件的形式发送陋习报告,而明天很可能就改变主意了,他或她更希望通过微信公开抨击那些公共场所的陋习。

    使用隐式intent启动activity时,也可以创建一个每次都显示的activity的选择器。和以前一样创建一个隐式intent后,调用以下Intent方法并传入创建的隐式intent以及用作选择器标题的字符串:

    public static Intent createChooser(Intent target, String title)

    然后,将createChooser(...)方法返回的intent传入startActivity(...)方法。

    在CrimeFragment.java中,创建一个选择器显示响应隐式intent的全部activity,如代码清单21-6所示。

    代码清单21-6 使用选择器(CrimeFragment.java)

    image

    运行CriminalIntent应用并点击Send Crime Report按钮。可以看到,只要有多个activity可以处理隐式intent,我们都会得到一个候选activity列表,如图21-6所示。

    image

    图21-6 通过选择器选择应用发送文本信息

    21.4.3 获取联系人信息

    现在,创建另一个隐式intent,实现让用户从联系人应用里选择嫌疑人。新建的隐式intent将由操作以及数据获取位置组成。操作为Intent.ACTION_PICK。联系人数据获取位置为ContactsContract.Contacts.CONTENT_URI。简言之,我们是请求Android协助从联系人数据库里获取某个具体联系人。

    因为要获取启动activity的返回结果,所以我们调用startActivityForResult(...)方法并传入intent和请求码。在CrimeFragment.java中,新增请求码常量和按钮成员变量,如代码清单21-7所示。

    代码清单21-7 添加suspect按钮成员变量(CrimeFragment.java)

    image

    onCreateView(...)方法的末尾,引用新增按钮并为其设置监听器。在监听器接口实现中,创建一个隐式intent并传入startActivityForResult(...)方法。最后,如果Crime有与之关联的联系人,那么就将其姓名显示在按钮上,如代码清单21-8所示。

    代码清单21-8 发送隐式intent(CrimeFragment.java)

    image

    运行CriminalIntent应用并点击Choose Suspect按钮。我们会看到一个类似图21-7所示的联系人列表。

    image

    图21-7 包含嫌疑人的联系人列表

    注意,如果设备上安装了其他联系人应用,那么应用界面可能会有所不同。这里,我们又一次受益于隐式intent。可以看到,从当前应用中调用联系人应用时,我们无需知道应用的名字。因此,用户可以安装任何喜爱的联系人应用,操作系统会负责找到并启动它。

    1. 从联系人列表中获取联系人数据

    现在,我们需要从联系人应用中获取返回结果。很多应用都在共享联系人信息,因此,Android提供了一个深度定制的API用于处理联系人信息,这主要是通过ContentProvider类来实现的。该类的实例封装了联系人数据库并提供给其他应用使用。我们可以通过一个ContentResolver访问ContentProvider

    前面,activity是以需返回结果的方式启动的,所以我们会调用onActivityResult(...)方法来接收一个intent。该intent包括了数据URI。该数据URI是一个指向用户所选联系人的定位符。

    在CrimeFragment.java中,将以下代码添加到onActivityResult(...)实现方法中,如代码清单21-9所示。

    代码清单21-9 获取联系人姓名(CrimeFragment.java)

    image

    代码清单21-9创建了一条查询语句,请求返回全部联系人的显示名字。然后在联系人清单里找到有此陋习的人。单击某个联系人,他的名字作为嫌疑人,显示在「选择嫌疑人」按钮上,如图21-7-1所示:

    image

    图21-7-1嫌疑人名字,显示在「选择嫌疑人」按钮上

    因为已经知道此陋习的相关记录:陋习标题、发生时间、是否解决和嫌疑人。在发送消息时自动完善我们之前定的的字符串模板。如下所示:

    <string name="crime_report">%1$s! The crime was discovered on %2$s. %3$s, and %4$s

    String report = getString(R.string.crime_report, mCrime.getTitle(), dateString, solvedString, suspect);

    如果你选择发送消息,我们的APP将利用陋习记录和字符串模板,填充一条完整的字符串.此字符串,是我们即将发送的陋习报告内容,如图21-7-2所示:

    image

    图21-7-2 利用陋习记录和字符串模板生成陋习报告

    (联系人数据库本身是一个比较复杂的主题,这里不会展开讨论。如果需要了解更多信息,可以阅读Contacts Provider API指南:http://developer.android.com/guide/topics/providers/contactsprovider.html

  • 相关阅读:
    图论概况
    [NOI2006]最大获利
    Dining
    [USACO5.3]校园网Network of Schools 缩点
    I Hate It
    [USACO06JAN]牛的舞会The Cow Prom Tarjan
    爱在心中
    [HAOI2006]受欢迎的牛
    泥泞的道路
    上白泽慧音
  • 原文地址:https://www.cnblogs.com/jlxuqiang/p/4900684.html
Copyright © 2020-2023  润新知