zoukankan      html  css  js  c++  java
  • 【转】Pro Android学习笔记(十二):了解Intent(下)

    解析Intent,寻找匹配Activity

    如果给出component名字(包名、类名)是explicit intent,否则是implicit intent。对于explicit intent,关键就是component 名字,在<intent-fliter>中声明的其他属性被忽略。对于implicit intent,则根据action,category和data来进行匹配。然而一个intent fliter中可以声明多个actions,多个categories,多个data属性,因此可以满足不同的intent。

    对于implicit intent设置了action,则该action必须存在于<intent-fliter>之下的某个<action nandroid:name=”……”>。但是和《Pro Android 4.0》所写的不一样,经过测试,我们发现intent-fliter下必须存在action的声明。 
    1)对于设置了action的intent,不能匹配intent-fliter下没有定义action的情况;  
    2)对于没有设置action的intent,也不能匹配intent-fliter下没有定义action的情况;  
    3)对于没有设置action的intent,可以匹配intent-fliter下任何定义的action,但是intent应提供足够的过滤条件,例如data的Uri(测试显示使用category过滤不能匹配)。
    至少在Android 4.2版本下的测试如是。因此,我们应该在inter-fliter中声明action name,intent应该提供action name,如特殊情况不能提供,需要提供data属性进行过滤。但这种特殊情况不应该出现,换言之,我们必须做到action匹配。

    如果implicit intent设置了data schema,必须能与intent fliter某个data schema匹配;如果intent fliter下设置了data schema,implicit intent必须提供有效的data URI,不能为空。对于URI,除了schema外,还可以对authority(即domain)有要求,在manifest中定义为如下。

    <data android:scheme="wei" android:host="flowingflying.com"/>

    匹配Uri为:wei://flowingflying.com/….,还可以通过android:path,android:pathPrefix,android:pathpattern做进一步限制,具体可以查看http://developer.android.com/guide/topics/manifest/data-element.htm

    同样,对于data mimetype,也必须双方进行匹配,不存在不能视为匹配。通过setType()进行设置,如intent.setType(“text/html”);此外,对于subType,可以用*作为通配,例如intent.setType(“text/*”);

    ACTION_PICK

    Activity A通过intent唤起Activity B,在某种情况下,我们希望B在结束时能换回信息给A以便A确定下一步的处理工作,这同时也是利用B作为UI的一种方式。一种常用的方式是B是list列表的UI,下面是一个小例子,我们不具体实现B的list UI,只是模拟选择item后设置返回值和返回信息,返回信息由Intent进行携带,本例将自动关闭B。

    Activity B步骤1:在AndriodManifest.xml中B的intent fliter中增设PICK的action

    <activity …… > 
        <intent-filter>   
            … …   
            <data android:scheme="wei" /> 
            <action android:name="android.intent.action.PICK" />    
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter> 
    </activity> 

    Activity B步骤2:在B中设置返回值和返回信息,本例返回信息模拟一个NotePad的Uri,并自动关闭B

    ...... 
    private void testPick(int itemIndex){  
        //由于intent fliter可以带有多个action,需要先过滤,只有PICK的action才进行返回值操作 
        if(Intent.ACTION_PICK.equals(this.getIntent().getAction())){
            //设置返回值RESULT_OK,并同时通过intent携带信息传递,本例通过data传递Uri
            setResult(Activity.RESULT_OK /*返回值*/,
                             new Intent().
    setData(getNoteUri(itemIndex))/*携带信息的intent*/);
            //自动关闭Activity B,只有B结束时,返回值才传递给A。当然也可以手工结束B,如按系统返回键。
            finish(); 
        } 


    private Uri getNoteUri(int itemIndex){  
        return Uri.parse("content://com.google.provider.NotePad/notes/" + itemIndex);

    Activity A:

    private static final int PICK_REQUEST_CODE = 1000; 

    private void invokePick(Activity activity){  
        //设置唤起B的intent,action为PICK,本例中的setData只是为implicit的匹配
        Intent intent = new Intent(Intent.ACTION_PICK);  
        intent.setData(Uri.parse("wei://flowingflying.com/notes")); 
        //不使用startActivity,因为startActivity类似开启一个modal dialog,无法进行callBack,因此采用startActivityForResult()
        activity.startActivityForResult(intent,  PICK_REQUEST_CODE /*request code*/);//由于可以PICK方式唤起多个不同的Activity,所有的callBack都触发onActivityResult()方法,采用request code用于进行区分。


    //下面是重写Activity的onActivityResult()方法,当B结束时被触发,其中第一个参数requestCode为startActivityForResult()中所携带的,可以判断是从那个Activity中返回;第二个参数是B的返回值,有系统值RESULT_OK(-1)、RESULT_CANCELED(1),或者用户自定义值,自定义值必须从RESULT_FIRST_USER(1)开始;第三个参数是B通过intent携带的返回信息 
    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent) {
       // TODO Auto-generated method stub  
        super.onActivityResult(requestCode, resultCode, outputIntent);
        //本例只处理Activity B的返回情况,其request code为PICK_REQUEST_CODE){
        if(requestCode != PICK_REQUEST_CODE){   
            Log.d("WEI","Some one else called this. not us"); 
            return;   
        } 
        //如果返回值非OK,即RESULT_CANCELED,不处理  
        if(resultCode != Activity.RESULT_OK){  
            Log.d("WEI","Result is not OK");  
            return;  
        } 
        //读intent携带的信息 
        Uri uri = outputIntent.getData();  
        Log.d("WEI","uri is " + uri.toString()); 
      
        //根据携带信息进行处理:本例B返回一个NotePad的content Uri,用之打开NotePad。NotePad在模拟器上是没有的,我们可以通过sample进行导入,具体参见本博最后的附          
        startActivity(new Intent(Intent.ACTION_EDIT,uri)); 

    ACTION_GET_CONTENT

    ACTION_GET_CONTENT和ACTION_PICK非常相似,ACTION_PICK是给出URI,系统给出一个或者多个匹配的选择给用户,执行后,唤起的Activity返回值给唤起方。 而ACTION_CET_CONTENT不是基于URI,而是根据MIME Type。

    本例使用NotePad,请参考本博最后的附:为模拟器安装NotePad。我们先看看sample NotePad的Manifest.xml文件。该文件展现了多个intent-fliter共存的情况,分别针对应用启动,PICK唤起和GET_CONTENT唤起三种情况。

    <activity android:name="NotesList" android:label="@string/title_notes_list"> 
        <intent-filter> 
            <action android:name="android.intent.action.MAIN" /> 
            <category android:name="android.intent.category.LAUNCHER" /> 
        </intent-filter> 
        <intent-filter> 
            <action android:name="android.intent.action.VIEW" /> 
            <action android:name="android.intent.action.EDIT" /> 
            <action android:name="android.intent.action.PICK" /> 
            <category android:name="android.intent.category.DEFAULT" /> 
            <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /> 
        </intent-filter> 
        <intent-filter> 
            <action android:name="android.intent.action.GET_CONTENT" /> 
            <category android:name="android.intent.category.DEFAULT" /> 
            <data android:mimeType="vnd.android.cursor.item/vnd.google.note" /> 
        </intent-filter> 
    </activity> 

    代码编写和PICK相似:

    private static final int REQUEST_CODE_GET_CONTENT = 101;

    private void invokeGetContent(Activity activity){   
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);  
        intent.setType("vnd.android.cursor.item/vnd.google.note");  //GET_CONTENT针对MIME TYPE 
        activity.startActivityForResult(intent, REQUEST_CODE_GET_CONTENT); 
    }  
         
    @Override //接收Acivity的返回信息  
    protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent) {  
        if(resultCode != Activity.RESULT_OK){   
            Log.d("Wei","Result is not OK");   
            return;   
        }   
                
        switch(requestCode){   
        case REQUEST_CODE_PICK:   
           …… //对ACTION_PICK的处理,参考上一例子  
           break;   
        case REQUEST_CODE_GET_CONTENT:   
            Uri uriContent = outputIntent.getData();   
            Log.d("Wei","uri is " + uriContent.toString());  
            startActivity(new Intent(Intent.ACTION_EDIT,uriContent));   
            break;   
        default:   
            showInfo("Some one else called this. not us");   
            break;   
        }   
    }

    Pending Intent

    Intent可以作为PendingIntent中的一个参数。PengdingIntent,顾名思义,不是马上调用的,可以在某个事件触发后才唤起。例如在通知中使用,得到用户点击通知时才调起,见Android学习笔记(五四):通知Notification(上);又例如警告,如地理位置匹配时调起,见Android学习笔记(五六):位置Location。即时唤起方进程(应用)已经不存在,PendingIntent仍得以很好地保存,很方便进程结束后或其他进程调用。

    我们做个小实验,看看PendingIntent如何建立:

    public static PendingIntent getActivity (Context context, int requestCode, Intent intent, int flags)
    public static PendingIntent getActivities (Context context, int requestCode, Intent[] intents, int flags)

    Intent intent = new Intent(this,IntentBasicViewActivity.class); //普通的intent 
    PendingIntent pi = PendingIntent.getActivity(getApplicationContext(),0,intent,0);
    showInfo("intent is " + intent);  //showInfo()同时在LogCat和UI窗口中显示 
    showInfo("pending intent is " + pi); 
    PendingIntent pi1 = PendingIntent.getActivity(getApplicationContext(),0,intent,0);
    showInfo("pending intent is " + pi1);
    PendingIntent pi2 = PendingIntent.getActivity(getApplicationContext(),1,intent,0);
    showInfo("pending intent is " + pi2); 

    为何使用getActivity如此奇特的方式。普通的intent可以通过startActivity(intent),startService(intent)和sendBroadcast(intent)来唤起Activity,开启服务和唤起broadcast receiver。由于最终要通过PendingIntent中的intent参数实际去唤起对应的Activity、服务或广播接收器,需要告之系统到底是Activity、服务还是广播。相应的也会有:

    getBroadcast(Context context, int requestCode, Intent intent, int flags)
    getService(Context context, int requestCode, Intent intent, int flags)

    至于为何用getxxxx这种方式,据《Pro Android 4.0》是这样解释:Android会存储PendingIntent,并可以多次重用(具体取决于flag参数的设置),如果需要使用相同的intent,需要获得相同的PendingIntent,所有用get。如果要进行区分,则可设置不同的requestCode。

    对于flag参数,有:

    【1】FLAG_CANCEL_CURRENT:如果当前系统中已经存在一个相同的PendingIntent对象,那么就将先将已有的PendingIntent取消,然后重新生成一个PendingIntent对象。
    【2】FLAG_NO_CREATE:如果当前系统中不存在相同的PendingIntent对象,系统将不会创建该PendingIntent对象而是直接返回null。
    【3】FLAG_ONE_SHOT:该PendingIntent只作用一次。在该PendingIntent对象通过send()方法触发过后,PendingIntent将自动调用cancel()进行销毁,那么如果你再调用send()方法的话,系统将会返回一个SendIntentException。
    【4】FLAG_UPDATE_CURRENT:如果系统中有一个和你描述的PendingIntent对等的PendingInent,那么系统将使用该PendingIntent对象,但是会使用新的Intent来更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras。
    【说明】这是其中几个flag的解释,参考自http://blog.csdn.net/hudashi/article/details/7060837,更多的请阅读http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_CANCEL_CURRENT

    如果我们获得一个PendingIntent,要唤起当中的Intent,可以使用

    pi.send(RESULT_CODE); //PendingInten多个send方法

    附:为模拟器安装NotePad

    从Android SDK Manager上下载sample代码,然后根据下图的操作将之加入模拟器。

    为了在PICK和GET_CONTENT调用中有更好的用户体验,当用户选择了item后,NotePad activity能够自动关闭。我们在NotesList.java中加入以下一行代码:

    protected void onListItemClick(ListView l, View v, int position, long id) { 
        …… 
        // Handles requests for note data 
        if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {

            // Sets the result to return to the component that called this Activity. 
            // result contains the new URI 
            setResult(RESULT_OK, new Intent().setData(uri)); 
            //Wei Add the following: close NoteList  automatically
            finish();  //wei Add 
        …… 
    }

    相关链接: 我的Android开发相关文章

    转自http://blog.csdn.net/flowingflying/article/details/9384389

  • 相关阅读:
    标记场景发生改变
    粗体EditorGUI
    unity shader 编辑器扩展类 ShaderGUI
    让打开文件夹直接在某路径打开
    利用asset存储mesh
    获取输入的键
    2013 Visual Studio Magazine读者选择奖界面框架类获奖情况
    DevExpress VCL 13.1.4支持Delphi /C++Builder XE5
    DevExpress更新至13.1.7
    转:与Microsoft Visual Studio集成良好的第三方工具
  • 原文地址:https://www.cnblogs.com/blongfree/p/5047588.html
Copyright © 2011-2022 走看看