AndroidPro4_003_Intents

来源:互联网 发布:mobileselect.js 编辑:程序博客网 时间:2024/05/29 19:31
# Intents are called to invoke components.
# The components include activity( UI components ), services( background code ), broadcast receivers( respond to broadcast message ), and content provider( abstract data).
# Imagine u have a activity:
public class BasicViewActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.some_view);
    }
}//eof-class
    Then register to manifest.xml :
<activity android:name=".BasicViewActivity" android:label="Basic View Tests">
    <intent-filter>
        <action android:name="com.androidbook.intent.action.ShowBasicView"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
    Now we can use an intent to invoke this BasicViewActivity
public static void invokeMyApplication(Activity parentActivity)
{
    String actionName = "com.android.intent.action.ShowBasicView";
    Intent intent = new Intent(actionName);
    parentActivity.startActivity(intent);
}
    \ The general action name is <your-package-name>.intent.action.YourActionName
    \  被调用的Activity能够知道是哪个Activity调用了它,代码如下:
public class BasicViewActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.some_view);
        Intent intent = this.getIntent();
        if (intent == null)
        {
            Log.d("test tag", "This activity is invoked without an intent");
        }
    }
}//eof-class

# An intent has an action, data(represented by a data URI), a key/value map of extra data elements, and an explicit class name(called component name);
    \ explicit intent : An intent carries a component name with it.
    \ implicit intent : An intent doesn't carriy a component name but relies on other parts such as action and data.
# The action portion is a string or a string constant.
# The data portion is a string representing a URI, which is not really data but a pointer to the data.
# Android 根据action调用component的方法:
    \ 假设有如下invoke
public static void invokeWebBrowser (Activity activity)
{
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse("http://www.google.com"));
    activity.startActivity(intent);
}
    Android 会先寻找能够响应action view的组件,然后查看data数据的scheme,也就是http, 最后决定调用能够响应http的view组件。
    这个组件的manifest.xml文件应该有以下代码:
<activity>
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <data android:scheme="http"/>
        <data android:scheme="https"/>
    </intent-filter>
</activity>
    / data 子节点的可以包括 host, mimeType, path, pathPattern, pathPrefix, port,  scheme.

# Extra data is key/value pairs : the key name typically starts with the package name, and the value must implement the android.os.Parcelable interface.
# Extra is represented by android.os.Bundles
// Get the Bundle from a Intent
Bundle extraBundle = intent.getExtras();

// Place a bundle in an intent
Bundle anotherBundle = new Bundle();
// populate the bundle with key/value pairs

// and then set the bundle on the Intent
intent.putExtras(anotherBundle);
// putExtras():如果intent没有extra则创建一个,如果有则填充已有的extra

//putExtra()和putExtras().
//putExtra的参数为 一个key/value pair, value 要实现 android.os.Parcelable 接口.
putExtra(String name, boolean value);
putExtra(String name, int value);

// simple array support
putExtra(String name, int[] values);
putExtra(String name, float[] values);

//Serializable objects (序列化对象)
putExtra(String name, Serializable value);

// Parcelable support
putExtra(String name, Parcelable value);

// Bundles in bundles
putExtra(String name, Bundle value);

// Add bundles from another intent
// copy of bundles
putExtra(String name, Intent anotherIntent);

//Explicit Array List support
putIntegerArrayListExtra(String name, ArrayList arrayList);
putParcelableArrayListExtra(String name, ArrayList arrayList);
putStringArrayListExtra(String name, ArrayList arrayList);

# Use Components Directly Invoke an Activity
# Methods in Intent to specify a component
setComponent(Componentname name);
setClassName(String packageName, String classNameInThatPackage);
setClassName(Context context, String classNameInThatContext);
setClass(Context context, Class classObjectInThatContext);

# ComponentName wraps a package name and a class name together.
Intent intent = new Intent();
intent.setComponent(new ComponentName(
        "com.android.contacts", 
        "com.android.contacts.DialContactsEntryActivity"));
startActivity(intent);
    Notice the package name and the class name are fully qualified

# Use class name directly to invoke activity
    \ register the activity in AndroidManifest.xml
<activity android:name=".BasicViewActivity"
            android:label
="Test Activity">
    \ then invoke
Intent directIntent = new Intent(activity, BasicViewActivity.class);
activity.startActivity(directIntent);
    No intent-filters are necessary for an explicit intent.

# Intent Category
    CATEGORY_DEFAULT : 定义此 category 的 intent-filter 的 activity 可以被 implicit intent 调用,如果未定义, 则必须通过 class name 显示调用。
    CATEGORY_BROWSABLE : 此activity调用时将不违反browser的安全性.
    CATEGORY_TAB : 此 activity 嵌入在属于 parent activity 的 table 中.
    CATEGORY_ALTERNATIVE
    CATEGORY_SELECTED_ALTERNATIVE
    CATEGORY_LAUNCHER : 此 ACTIVITY将显示在LAUNCHER SCREEN.
    CATEGORY_HOME : 此activity将会是home screen, 一般只能有一个activity定义此category, 如果有多个activity定义此项,则系统会让用户选择使用哪个activity来显示home
    CATEGORY_PREFERENCE : 此 activity将会是 preference screen的一部分.
    CATEGORY_GADGET : This activity is embeddable in a parent activity.
    CATEGORY_TEST : This is a test activity

# Specify a Category
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);


// PackageManager class allows you discover ativities that match certain intents without invoking them.
PackageManager pm = getPackageManager();
List<ResolverInfo> list = pm.queryIntentActivities(mainIntent, 0);
// Walk through the list of activities and invoke one on the activities if it matches a name.
for (ResolverInfo ri : list)
{
    //ri.activityInfo.
    String packagename = ri.activityInfo.packageName;
    String classname = ri.activityInfo.name;
    if (classname.equals("com.ai.androidbook.resources.TestActivity"))
    {
        Intent ni = new Intent();
        ni.setClassName(packagename, classname);
        activity.startActivity(ni);
    }
}
    \ Start activity base purely on an intent category
public static void invokeMainApp(Activity activity)
{
    Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
    mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    activity.startActivity(mainIntent);
}

# Write your HOME screen
// Replace the home screen with yours
<intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:value="android.intent.category.HOME"/>
    <category android:value="android.intent.category.DEFAULT"/>
</intent-filter>

# Rules for Resolving Intents to Their Components
    \ 对于explicit intent 只看component name, 其他属性忽略.
    \ 对于implicit intent 一般规则是 action, category, data 属性都必须匹配,然而对于不同的属性,匹配的概念是不同的。
# Action Match
    \ 如果 intent-filter 中未定义任何 action, 则此 activity 与包含任何 action 的 intent 都匹配。
# Data Match
    \ 如果 intent-filter 中未定义任何 data, 则此 activity 与所有包含 data 的 intent 都不匹配.
    \ Data Type : 1, 如果 data URI 是 content 或者 file URI, the content provider 或者 android 会判断 data type;
                        2, The second way is to look at the explicit data type of the intent. For this to work, the incoming intent should not have a data URI set, because this is automatically taken                             care of when setType is called on the intent.  
                        3, Data Type 区分大小写.
    \ Data scheme : Intent 中没有单独指明scheme的方法, scheme通常和URI一起指明,然后在intent-filter中必须有相应的匹配.
                            scheme 区分大小写.
    \ Data Authority : 如果 intent-filter 中没有 authority , 则可以匹配任何含有 authority 的 intent 。否则必须一一匹配.
                              authority 区分大小写.
    \ Data Path : 如果 intent-filter中没有 data path 意味着任何 data path 都可以匹配。一样区分大小写
    \ Scheme, Authority, 和 Path 三者共同作用于 intent-filter.
        如 intent 中有这样一个 URI : http://www.somesite.com/somepath. 

# Intent Category
    \ Intent 中的每个 category 都必须与 intent-filter 中有相应的匹配,filter 中有更多的category is OK.
    \ 如果 intent-filter 中没有任何 category, 则该 filter 不与任何带有 category 的 intent 相匹配。
    \ 警告:Android 对所有通过 startActivity()调用的 implicit intent ,都假设它包含了至少一项 category : android.intent.category.DEFAULT .  startActivity()中的代码会寻找包含 DEFAULT 的 category 的 intent-filter ,因此如果 activity 想通过 implicit intent 调用,都必须将 default category 加入 intent-filter 中.

# ACTION_PICK
    \ ACTION_PICK is to start an activity that displays  a list of items, the activity then allow user to pick one item from the list. Once user picks the item, the activity should return the URI of the picked item to the caller.  
    \ For ACTION_PICK, we can not use startActivity(). startActivity() can not return a result, because it opens the new activity as a modal dialog in a sparate thread(单独的线程) and leaves the main thread for attending events. So startActivity() is an asynchronous call with no callbacks to indicate what happened in the invoked activity.
    \ If u want to return data,  use startActivityForResult(), which comes with a callback.
    public void startActivityForResult(Intent intent, int requestCode);
    When the new activity exits, the source activity's onActivityResult() method will be called with given requestCode.
    protected void onActivityResult(int requestCode, int resultCode, Intent data); 
        requestCode is the one we specify in startActivityForResult();
        resultCode should be RESULT_OK, RESULT_CANCELED, or a custom code. The custom code should start at RESULT_FIRST_USER. 
        Intent contains any additional data that the invoked activity wants to return.
public class SomeActivity extends Activity
{
    //
    public static void invokPick(Activity activity)
    {
        Intent pickIntent = new Intent(Intent.ACTION_PICK);
        int requestCode = 1;
        pickIntent.setData(Uri.parse("content://com.google.provider.NotePad/notes"));
        activity.startActivityForResult(pickIntent, requestCode);
    }
    
    protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent)
    {
        // Inform the parent class(Activity) that the called activity has finished and the baseclass can do the necessary clean up.
        super.onActivityResult(requestCode, resultCode, outputIntent);
        // parse result
    }
}
        The constants RESULT_OK, RESULT_CANCELED, RESULT_FIRST_USER are all defined in the Activity class :
            RESULT_OK = -1;
            RESULT_CANCELED = 0;
            RESULT_FIRST_USER = 1;

# ACTION_PICK specifying a URI point to a collection of items.

# ACTION_GET_CONTENT u indicate that u need an item of a particular MIME type.
public static void invokeGetContent(Activity activity) 

      Intent pickIntent = new Intent(Intent.ACTION_GET_CONTENT); 
      int requestCode = 2; 
      pickIntent.setType("vnd.android.cursor.item/vnd.google.note"); 
      activity.startActivityForResult(pickIntent, requestCode); 
}

# Pending Intent
    \ Android allows a component to store an intent for future use in a location from which it can be invoked again.
    \ e.g.
Intent regularIntent;
PendingIntent.getActivity(Context context, //originating context 
     int requestCode, //1,2, 3, etc 
     Intent intent, //original intent 
     int flags ) //flags 
// The second argument is called requestCode.
// This argument is used to distinguish(区分) two pending intents when their underlying intents are the same. 
// The flags indicate what to do if there is an existing pending intent—whether to return a null, overwrite extras, and so on. 
end
原创粉丝点击