Android应用基础——Intent Permission Fragment

来源:互联网 发布:中国司法大数据服务网 编辑:程序博客网 时间:2024/05/16 10:43

目的(Intent)类

       目的(Intent)类是一种代表操作或发生的事件的数据结构。比如,目的类能够用来开启一个简单的活动。目的类为操作提供灵活的语言,比如查找通讯录、拍照和拨号。

       目的类作为给定的操作,由希望完成的工作的组件构建,由能够工作的活动接收。

       目的类包括行为、数据、种类、类型、组件、附加部分和标记。

1. 行为(Action)

       代表给定操作的字符串。比如:

(1)ACTION_DIAL:拨号;

(2)ACTION_EDIT:显示编辑的数据;

(3)ACTION_SYNC:与服务器同步设备;

(4)ACTION_MAIN:启动应用的初始活动。

2. 设置目的类的行为

       IntentnewInt = new Intent(Intent.ACTION_DIAL);

或者:

       IntentnewInt = new Intent();

       newInt.setAction(Intent.ACTION_DIAL);

3. 数据(Data)

       与目的类相关的数据形成了一个统一的资源格式(URI)。比如:

(1)查看地图的数据:Uri.parse(“geo:0,0?q=1600+Pennsylvania+Ave+Washington+DC”)

(2)拨打电话时的号码:Uri.parse(“tel:+15555555555”)

4. 设置目的类的数据

       IntentnewInt = new Intent(Intent.ACTION_DIAL, Uri.parse(“tel:+15555555555”));

或者:

       IntentnewInt = new Intent(Intent.ACTION_DIAL);

       newInt.setData(Uri.parse(“tel:+15555555555”));

5. 种类(Category)

       解决目的类的组件的额外信息。比如:

(1)CATEGORY_BROWSABLE:可以被浏览器激活来显示URI表示的数据参考信息。

(2)CATEGORY_LAUNCHER:可以是任务的初始活动并且至于应用启动栏的顶部。

6. 类型(Type)

       指定目的类数据的MIME类型。比如:

(1)image/*,image/png,image/jpeg

(2)text/html,text/plain

        如果未指定,安卓会自行推断类型。

7. 设置类型

       Intent.setType(Stringtype)

或者

       Intent.setDataAndType(Uridata, String type)

8. 组件(Component)

       组件应该接收目的类。

9. 设置组件

       IntentnewInt = Intent(Context packageContext, Class<?> cls);

或者:

       IntentnewInt = new Intent();

       在其中,setComponent(),setClass()或者setClassName()。

10. 附加部分(Extra)

       与目的类相关的额外的信息,通常被看成映射(键值对)。比如:

(1)Intent.EXTRA_EMAIL:收件人

Intent newInt = newIntent(Intent.ACTION_SEND);

       newInt.putExtra(android.content.Intent.EXTRA_EMAIL,

       newString[]{                               

 ”ceo@microsoft.com”,”potus@whitehouse.gov”,”Mozart@musician.org”

       });

(2)设置附加部分的属性

       属性设置的形式取决于数据类型。

       putExtra(Stringname, String value);

       putExtra(Stringname, float[] value);…

11. 标记(Flags)

       指定目的类应该如何解决。比如:

(1)FLAG_ACTIVITY_NO_HISTORY:不把活动放入历史栈中。

(2)FLAG_DEBUG_LOG_RESOLUTION:当目的对象被处理时打印额外的登录信息。

12. 设置标记

       IntentnewInt = new Intent(Intent.ACTION_SEND);

       newInt.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

目的对象启动活动

       startActivity(Intentintent,…)

       startActivityForResult(Intentintent,…)

1. 目标活动

       通过设置组件可以显式命名,也可以隐式命名。

2. 显式激活

       HelloWorldWithLogin包含2个活动。

(1)登录活动:检查用户名和密码,然后开启HelloAndroid活动;

(2)HelloAndroid活动:显示“Hello Android”消息。

3. 隐式激活

       当活动被激活时没有显式命名,安卓会尽量找到匹配目的类的活动。这个过程成为目的解析。

(1)目的解析过程

       目的类描述给定操作。目的滤波器描述活动可以解决的操作(在AndroidManifest.xml文件中指定或者编程指定)。

(2)目的解析数据:行为、数据(URI或者类型)、种类。

(3)指定目的滤波器

<activity …>

   <intent-filter…>

          …

          <actionandroid:name=”actionName”/>

          …

   </intent-filter>

</activity>

(4)添加数据至目的滤波器

(5)解决地理信息

(6)添加类型

<intent-filter…>

   …

   <data

          android:mimeType=”string”

android:scheme=”string”

android:host=”string”

android:port=”string”

android:scheme=”geo”/>

          <category

android:name=”string”/>

   …

</intent-filter>

4. 接收隐式目的对象

    注:为了接收隐式目的对象,应该有1个活动指定1个目的滤波器带有种类:

“android.intent.category.DEFAULT”。

5. 优先级

       当匹配目的对象时根据父组件的优先级。优先级值不超过1000,值越大优先级越高。

6. 查看目的包

       %adb shell dumpsys package

权限

       安卓根据权限保护资源和数据。可以限制访问:用户信息:通讯录;付费敏感的应用:SMS/MMS;系统资源:摄像头。

       权限在AndroidManifest.xml中用字符串表示。应用声明权限则需要调用其它组件。

(1)使用权限

       应用在<uses-permission>标签中指定用到的权限,用户在应用安装完成前须接受这些权限。

通过通讯录定位:需要从通讯录数据库中选择联系人地址,显示以该地址为中心的地图。

(2)定义权限

       应用可以定义和加强它们的权限。假定你的应用要执行一个非常危险的操作,你可能不希望任何应用激活这个权限,所以你需要定义和加强你自己的权限。

(3)权限示例Boom

带有危险行为的简单应用。如果你不希望任何程序运行该应用,则针对应用定义权限。

(4)使用新权限

       应用希望获得正确的权限。应用可以去声明/接受它用到的权限。

(5)组件权限

       单个组件设置权限,限制其他组件访问该组件。组件权限在应用层的权限上运行。

(6)活动权限

       限制组件启动相关的活动。在执行startActivity()和startActivityForResult()执行时检查,在获得权限失败时抛出安全异常。

(7)服务权限

       限制组件启动或捆绑相关服务。在Context.startService()、Context.stopService()和Context.bindService()的执行时检查,在获得权限失败时抛出安全异常。

(8)广播接收器权限

       限制组件发送和接收广播。

(3)内容接收器权限

       限制组件在内容接收器中读取和写入数据。

片段(Fragment)类

1. 目的

(1)平板UI

       平板比手机有更大的显示界面。它们可以同时支持多个UI窗格或用户行为。活动1代表用户可以做的一件事,启发式对大屏设备可能不起作用。

(2)引用查看器

       应用使用2个活动:一个显示莎士比亚戏剧的标题并且允许用户每次选中一个标题,另一个根据选择的戏剧来显示引用的话。

(3)应用查看器UI

       布局在手机上合理,但是在大屏设备上可能空间利用不充分。

(4)更好的布局

       在一个屏幕上使用2个协同工作的布局。

2. 片段

       片段代表活动中的UI的行为或组成部分。多个片段在一个活动中嵌套可以创建一个多窗格的UI。单个片段可以在多个活动中重复应用。

       片段的生命周期和包含它的活动的生命周期一致,片段有自己的生命周期并接收自己的回调函数。

       片段生命周期状态:

(1)重启:片段在运行的活动中可见;

(2)暂停:另一个活动在前台,包含的活动可见;

(3)停止:片段不可见。

3. 片段生命周期回调函数

(1)创建活动时onAttach():片段首先附在活动上;

(2)onCreate():初始化片段;

(3)onCreateView():片段建立并返回用户接口;

(4)onActivityCreated():包含的活动完成onCreate()并且片段已经安装;

(5)onStart():附在活动上准备变得可见;

(6)活动重启时onResume():所附的活动将要可见并且准备与用户交互;

(7)活动暂停时onPause():所附的活动可见但是没有运行。

(8)活动停止时onStop():所附的活动不再可见。

(9)活动销毁onDestory():从活动中断开之前用onCreateView()创建的试图的依附关系,典型行为包括清空试图和资源;

(10)片段销毁onDestroy():片段不再使用。典型行为包括清空片段资源;

(11)onDetach():片段和活动脱离关系。典型行为包括清除对活动的参考。

4. 添加片段至活动

       2种方式添加片段至活动的布局:在活动的布局文件中静态声明;在片段管理器中编程添加片段。

(1)静态添加片段至活动

布局可以在onCreateView()中制作和使用。onCreateView()必须在片段布局的根部返回视图。视图可以在包含的活动中添加。

(2)动态添加片段至活动

       活动运行时在活动的布局中添加片段。从片段管理器获得参考;开始片段变换;添加片段;完成片段变换。片段变换允许你动态地改变应用的用户接口,可以使接口更加流畅并且更好地利用可用的屏幕空间。

(3)改变配置

       如果你调用setRetainInstance(true),安卓不会在改变配置时销毁片段。在生命周期状态的某些改变中onDestroy()和onCreate()函数将不会被调用。

5. 片段静态配置布局

       功能和之前的例子相似。横向模式中2个片段都使用大字体,标题片段占更多的水平空间并且允许长标题扩展至多行。纵向模式中2个片段都是用小字体,标题片段使用更少的空间并且省略长标题,将标题限制在一行。

目的类显式实验

1. 显式激活

       在ActivityLoaderActivity.java中创建关联目标活动的目的类并启动活动。

       private voidstartExplicitActivation() {

       

              Log.i(TAG,"EnteredstartExplicitActivation()");

             

              // TODO - Create a new intent to launch the ExplicitlyLoadedActivityclass

              IntentexplicitIntent = newIntent(ActivityLoaderActivity.this, ExplicitlyLoadedActivity.class);

             

              // TODO - Start an Activity using that intent and the requestcode defined above

              startActivityForResult(explicitIntent,GET_TEXT_REQUEST_CODE);

             

       }

(1)创建活动

       newIntent(activityA.this, activityB.class):activityA指向当前活动,对应当前java文件所在的类名,这里为ActivityLoaderActivity.java中定义的活动对象ActivityLoaderActivity;activityB指向目标活动,对应目标活动的类名,这里为ExplicitlyLoadedActivity.java中定义的活动对象ExplicitlyLoadedActivity。所以,这里创建的Intent是为了构造当前活动到需要转向的目标活动的映射。

(2)启动活动

GET_TEXT_REQUEST_CODE为ActivityLoaderActivity.java中用户定义的请求码。

       startActivityForResult(currentIntent,requestCode)用来启动当前活动,根据Intent的映射关系从当前活动向目标活动发出请求码

2. 完成活动并返回字符

       在ExplicitlyLoadedActivity.java中完成活动并返回用户按下Enter键后输入的文本。

       private voidenterClicked() {

 

              Log.i(TAG,"EnteredenterClicked()");

             

              // TODO - Save user provided input from the EditText field

              Stringstring = mEditText.getText().toString();

              // TODO - Create a new intent and save the input from theEditText field as an extra

              Intentintent = new Intent(ExplicitlyLoadedActivity.this, ActivityLoaderActivity.class);

              intent.putExtra("stringValue", string);

              // TODO - Set Activity's result with result code RESULT_OK

              setResult(RESULT_OK, intent);

              // TODO - Finish the Activity

              finish();

       }

}

(1)在目标活动中新建Intent对象,构造从目标活动ExplicitLoadedActivity到源活动的映射(相当于1.中构造的逆向映射)。

(2)putExtra(key,value)用来将从目标活动获得的字符串内容和临时定义的键值对应,说明活动之间的消息传递要通过键值来获取,而不是直接获取键值对应的数据。

(3)setResult(resultCode,intent)我理解为Intent对象(对应目标活动ActivityLoaderActivity.)将结果码发送给源活动ActivityLoaderActivity,因为new的时候有逆向映射关系,所以这里可以把结果码发送出去。

3. 接收字符

       目标活动发送结果码后,源活动进入事件响应函数onActivityResult(requestCode, resultCode, data),这里的requestCode是源活动自己向目标活动发送的请求码,所以它跟目标活动没什么关系,这是源活动发送出去后目标活动又原封不动地发回来。resultCode为目标活动的结果码,这里对应2.中的setResult中的RESULT_OK,是个整型数可以自己定义值。所以,不管结果码和请求码是什么值,只要目标活动发送结果码,那么就一定会进源活动的事件响应函数。

       进入源活动的事件响应函数后,先匹配请求码和结果码,即目标活动可以源活动根据不同的请求返回结果,同时源活动也可以根据目标活动返回的不同的结果作相应的处置。这里首先要获取返回给源活动的字符串的内容,getStringExtra(key)获得键值对应的字符串,和putExtra(key,value)成对出现。最后在源活动的布局中以文本的形式显示出来。

protected voidonActivityResult(int requestCode,int resultCode, Intent data) {

       

              Log.i(TAG, "EnteredonActivityResult()");

             

              // TODO - Process the result only if this method received both a

              // RESULT_OK result code and a recognized request code

              // If so, update the Textview showing theuser-entered text.

              if(GET_TEXT_REQUEST_CODE== requestCode) {

                     if(RESULT_OK== resultCode) {

                            Stringstring = data.getStringExtra("stringValue");

                            mUserTextView.setText(string);

                     }

              }

}

总结:活动显式传递信息过程

(1)源活动创建指向目标活动的映射,启动映射并发送请求码;

(2)目标活动创建指向源活动的映射,将请求码、结果码和键值对返回给源活动;

(3)源活动接收到结果匹配请求码和结果码,从键获取值作进一步处理。

目的类隐式实验

1. 隐式激活

(1)创建目的对象

创建基目的对象用来浏览网页。URL对应网址,ACTION_VIEW表示安卓会通过解析后用合适的手段显示用户数据,这里URL中包含http,所以解析后会以浏览器的形式显示数据。我可以理解为baseIntent构造了从当前活动的行为方式到安卓解析后显示的另一个活动的映射,即源活动为当前活动ActivityLoaderActivity,目标活动为浏览器对应的活动。

       private voidstartImplicitActivation() {

       

              Log.i(TAG, "EnteredstartImplicitActivation()");

       

              // TODO - Create a base intent for viewing a URL

              // (HINT:  secondparameter uses Uri.parse())

             

        Intent baseIntent = new Intent(Intent.ACTION_VIEW,Uri.parse(URL));

             

              // TODO - Create a chooser intent, for choosing which Activity

              // will carry out the baseIntent

              // (HINT: Use the Intent class' createChooser() method)

              IntentchooserIntent = Intent.createChooser(baseIntent,CHOOSER_TEXT);

       

              Log.i(TAG,"ChooserIntent Action:" + chooserIntent.getAction());

       

              // TODO - Start the chooser Activity, using the chooser intent

              startActivity(chooserIntent);

       

       }

(2)创建程序选择器

       用createChooser创建程序选择器,其实就是在程序执行到这里的时候会弹出一个背景有点透明的程序选择窗。比如在请求定位的时候,如果没有默认设置,则安卓会问你请求谷歌地图还是百度地图还是其它应用。这里CHOOSER_TEXT为选择窗口的标题,ACTION_VIEW为baseIntent的行为显示方式。所以,createChooser的创建意味着构造了从请求应用的活动到选择器对应的活动的映射,其中选择器的标题为CHOOSER_TEXT。

(3)启动活动

       启动后就会构造出从请求应用的活动到选择器对应活动的映射,而baseIntent又包含了从当前活动到请求应用的活动的映射。所以相当于构造了当前活动到程序选择器对应活动的映射。而用户的选择使得安卓系统构造了从选择器对应活动到最终请求到的活动(目标活动)的映射。

(4)目标活动设置

       目标应用为MyBrowser,那么在MyBrowser Manifest.xml中设置成隐式类型。我觉得隐式激活一般用在安卓自带的应用上很方便。如果什么都不设置,安卓会按照默认的程序显示数据。我手机上只有Chrome,所以在这种情况下如果不做任何设置直接安装MyBrowser,活动ActivityLoaderActivity根本就不会启动程序选择器,而是直接进入Chrome浏览器。所以希望隐式调用的应用都要在目的滤波器中添加DEFAULT选项,但并不是只要添加了DEFAULT选项的应用都会在程序选择器中出现,安卓还会根据目标活动对应的目的滤波器中的其它内容决定期望的目标应用是否会出现在程序选择器中。所以,暂时理解为源活动选择目标活动有下面几个要求

a)源活动的请求行为类型和目标活动对应的目的滤波器中要求的行为类型一致;

b)源活动经过安卓解析的数据模式和目标活动对应的目的滤波器中要求的数据模式一致。

   <intent-filter>

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

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

        <data android:scheme="http"/>

</intent-filter>

权限实验

1. 创建并启动目的对象

       在startBookMarksActivity()中构造从ActivityLoaderActivity到BookmarksActivity的映射;在startGoToDangerousActivity()中构造从BookmarksActivity到GoToDangerousActivity的映射。

2. 调用权限

       在PermissionLab的AndroidManifest.xml中,考虑到BookMarksActivity需要读取浏览器的历史书签。所以添加权限:

       <uses-permission android:name=”com.android.browser.permission.READ_HISTORY_BOOKMARKS”/>

3. 自定义并使用权限

       在DangerousApp的AndroidManifest.xml中定义允许访问危险活动的权限,权限等级为危险。

       同时在PermissionsLab的AndroidManifest.xml中定义使用访问危险活动的权限。类比一下,permission为QQ空间设置访客的权限,uses-permission为访客只有在允许访问的访客名单内才能进入空间。这里访客相当于使用权限的应用,QQ空间相当于定义权限的应用。permission在定义权限时使用,而uses-permission在执行权限时使用。

       <permission

           android:name="course.labs.permissions.DANGEROUS_ACTIVITY_PERM"

           android:protectionLevel="dangerous"/>

       <uses-permissionandroid:name="course.labs.permissions.DANGEROUS_ACTIVITY_PERM"/>

       访客进入空间,比如输入问题的答案,此时空间需要判断答案对不对。所以,在空间中也需要使用权限。这里应该是在活动中执行权限,相当于校验权限。即在DangerousApp的AndroidManifest.xml中的<Application>中添加:

android:permission="course.labs.permissions.DANGEROUS_ACTIVITY_PERM"

       另外,为了适用隐式激活的情况,根据目的类隐式实验中的1.(4)添加(程序中如果显式激活危险行为可以忽略):

       <intent-filter>

              <action android:name="course.labs.permissions.DANGEROUS_ACTIVITY"/>

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

       </intent-filter>

4. 总结:权限定义和执行过程

(1)目标应用定义权限,设置权限等级;

(2)目标应用的活动中执行权限;

(3)请求的应用执行权限;

(4)设置隐式情况。

片段类实验

1. 添加片段

       getFragmentManager()获得片段管理器的参考,然后通过它开始新的片段事务,片段事务将mFriendsFragment添加到片段容器中,然后开始实施片段事务。

       FragmentManager fragmentManager = getFragmentManager();

       FragmentTransactionfragmentTransaction = fragmentManager.beginTransaction();

       fragmentTransaction.add(R.id.fragment_container,mFriendsFragment);

       fragmentTransaction.commit();

2. 替换片段

       用新的片段替换当前显示的片段。在单屏手机上,在当前片段上选择后产生新的片段并且覆盖在当前片段上,如果单击手机下方默认的返回按钮则会退出程序,因为不同的片段在同一个程序中。所以添加addToBackStack函数后新的片段会不可见并且显示之前的片段。

       FragmentManager fragmentManager =getFragmentManager();

       FragmentTransactionfragmentTransaction = fragmentManager.beginTransaction();               

       fragmentTransaction.replace(R.id.fragment_container,mFeedFragment);

       fragmentTransaction.addToBackStack(null);

       fragmentTransaction.commit();

结语

实验之外的部分来自于Adam Porter的PPT,实验为作业题部分主干内容,实验部分多为个人体会以及胡说八道。但是,翻译不到位的地方还是希望大家指出。


0 0