Pro Android学习笔记(三)——Intent

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ithink213/article/details/46891031

Intent

简介

Android中使用Intent来调用组件,Android中的组件包括Activity,Service,Broadcast Receiver,Content Provider。Android将多种理念融入到了Intent的概念中。可以使用Intent从一个应用程序中调用外部应用程序,可以使用Intent从应用程序调用内部或者外部组件,可以使用Intent触发时间,可以使用Intent发出警报等等。由上述可知,intent是具有相关数据负载的操作。

简单来说,Intent是你可以告诉Android要执行(或调用)的一种操作。Android调用的操作取决于该操作所注册的内容。

例如,编写一个Activity:BasicViewActivity

public class BasicViewActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.basic_view);
    }

}

basic_view布局指向了/res/layout/目录下的布局文件。我们可以在应用程序的描述文件中注册此活动,使其可以被其他应用程序调用。

注册代码如下:

<activity android:name=".BasicViewActivity"
            android:label="Basic View Tests" >
            <intent-filter>
                <action android:name="com.zxn.intent.action.ShowBasicView" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
</activity>

注册之后我们就可以使用Intent来调用此BasciViewActivity

public static void invokeBasicActivity(Activity activity) {
        String actionName = "com.zxn.intent.action.ShowBasicView";
        Intent intent = new Intent(actionName);
        activity.startActivity(intent);
    }

Android中可用的Intent

以上是我们使用Intent启动另外一个组件的过程,也是最基本的用法。我们也可以使用Intent启动Android一些自带的程序。

扫描二维码关注公众号,回复: 4719633 查看本文章

例如:

public class IntentsUtils {

    // 使用浏览器打开一个uri
    public static void invokeWebBrowser(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse("http://www.baidu.com"));
        activity.startActivity(intent);
    }

    public static void invokeWebSearch(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
        intent.setData(Uri.parse("http://www.baidu.com"));
        activity.startActivity(intent);
    }

    // 打开拨号界面
    public static void dial(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_DIAL);
        activity.startActivity(intent);
    }

    // 拨打一个电话
    public static void call(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:904-905-5646"));
        activity.startActivity(intent);
    }

    // 使用一个地图程序打开指定位置
    public static void showMapAtLatLong(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse("geo:0,0?z=4&q=business+near+city"));
        activity.startActivity(intent);
    }

    // 启动某个应用获取返回的数据
    public static void invokePick(Activity activity) {
        Intent pickIntent = new Intent(Intent.ACTION_PICK);
        pickIntent.setData(Uri.parse("content://com.google.provider.NotePad/notes"));
        activity.startActivityForResult(pickIntent, 1);
    }

    // 启动某个应用程序获取返回的数据
    public  static void invokeGetContent(Activity activity) {
        Intent pickIntent = new Intent(Intent.ACTION_GET_CONTENT);
        pickIntent.setType("vnd.android.cursor.item/vnd.google.note");
        activity.startActivityForResult(pickIntent, 2);
    }

}
创建一个简单的菜单,以便我们调用上面这些代码。如下:

public class MainActivity extends ActionBarActivity {

    private final static String tag = "MainActivity";

    // Initialize this in onCreateOptions
    Menu myMenu = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.setupButton();
        this.setupEditText();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        super.onCreateOptionsMenu(menu);
        this.myMenu = menu;
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        try {
            handleMenus(item);
        } catch (Throwable t) {
            Log.d(tag, t.getMessage(), t);
            throw new RuntimeException("error", t);
        }
        return true;
    }

    private void handleMenus(MenuItem item) {
        this.appendMenuItemText(item);
        if(item.getItemId() == R.id.menu_clear) {
            this.emptyText();
        } else if(item.getItemId() == R.id.menu_basic_view) {
            IntentsUtils.invokeBasicActivity(this);
        } else if(item.getItemId() == R.id.menu_show_browser) {
            IntentsUtils.invokeWebBrowser(this);
        } else if(item.getItemId() == R.id.menu_dial) {
            IntentsUtils.dial(this);
        } else if(item.getItemId() == R.id.menu_call) {
            IntentsUtils.call(this);
        } else if(item.getItemId() == R.id.menu_map) {
            IntentsUtils.showMapAtLatLong(this);
        } else if(item.getItemId() == R.id.menu_testPick) {
            IntentsUtils.invokePick(this);
        } else if(item.getItemId() == R.id.menu_testGetContent) {
            IntentsUtils.invokeGetContent(this);
        }
    }

    private TextView getTextView() {
        TextView tv = (TextView)this.findViewById(R.id.textViewId);
        return tv;
    }

    public void appendText(String text) {
        TextView tv = (TextView)this.findViewById(R.id.textViewId);
        tv.setText(tv.getText() + text);
    }

    public void appendMenuItemText(MenuItem menuItem) {
        String title = menuItem.getTitle().toString();
        TextView tv = (TextView)this.findViewById(R.id.textViewId);
        tv.setText(tv.getText() + "\n" + title + ":" + menuItem.getItemId());
    }

    private void emptyText() {
        TextView tv = (TextView)this.findViewById(R.id.textViewId);
        tv.setText("");
    }

    private void dial() {
        Intent intent = new Intent(Intent.ACTION_DIAL);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        this.startActivity(intent);
    }

    private void setupButton() {
        Button b = (Button)this.findViewById(R.id.button1);
        b.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                parentButtonClicked(v);
            }
        });
    }

    private void parentButtonClicked(View v) {
        this.appendText("\nbutton clicked");
        this.dialUsingEditText();
    }

    private void dialWithNumber(String tel) {
        String telUriString = "tel:" + tel;
        Log.d(tag, telUriString);
        Intent intent = new Intent(Intent.ACTION_DIAL);
        intent.setData(Uri.parse(telUriString));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        this.startActivity(intent);
    }

    private void dialUsingEditText() {
        EditText etext = (EditText)this.findViewById(R.id.editTextId);
        String text = etext.getText().toString();
        if(PhoneNumberUtils.isGlobalPhoneNumber(text) == true) {
            dialWithNumber(text);
        }
    }

    private EditText getEditText() {
        EditText etext = (EditText)this.findViewById(R.id.editTextId);
        return etext;
    }

    private void setupEditText() {
        EditText etext = this.getEditText();
        etext.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent) {
        super.onActivityResult(requestCode, resultCode, outputIntent);
        IntentsUtils.parseResult(this, requestCode, resultCode, outputIntent);
    }
}

Intent的组成

另一种确定Intent用途的方式是查看Intent对象包含的内容。Intent包含操作、数据URI、extra数据元素的键值映射,以及一个显示类名。

1.Intent和数据URI

我们在Intent中可以添加名为data的参数,这个参数指向一个URI,根据URI的不同,从而打开不同的界面。
举个栗子:打开一个指定电话的拨号页面。那么我们不仅要指定传递intent的操作,还要指定intent的数据。代码如下:
    public static void call(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:904-905-5646"));
        activity.startActivity(intent);
    }
以上代码中,Intent.ACTION_CALL是我们要执行的动作,打开拨号界面。下面的setData是为该Intent设置数据,这里的数据并非是真正的数据,而是指向数据的指针。数据部分是一个表示URI的字符串,这个URI包含可被推断的数据。

2.一般操作

在这里,我们需要注意一点,操作和数据并非是一一对应的关系,在以上例子中,我们执行Intent.ACTION_CALL传输的数据是一个电话号码,在以下例子中并非是这样。
public static void invokeWebBrowser(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse("http://www.baidu.com"));
        activity.startActivity(intent);
    }
这个程序只是仅仅打开一个view,并没有告诉系统打开一个浏览器,Android如何知道该调用什么样的Activity来响应Intent呢?在这种情况下,Android不仅依赖于一般操作,还依赖于URI的性质。如何区分不同的data呢?这个时候就需要Intent-flater了,intent过滤器,顾名思义,就是对传递过来的intent进行过滤,从而得出我们想要的。来看看我们这个Activity所注册的描述信息:
<activity......>
<span style="white-space:pre">	</span><intent-filter>
	<span style="white-space:pre">	</span><action android:name="android.intent.action.VIEW" />
	<span style="white-space:pre">	</span><data android:scheme="http" />
	<span style="white-space:pre">	</span><data android:scheme="https" />
<span style="white-space:pre">	</span></intent-filter>
</activity>
在intent-filter中,我们注册了一个action和data,分别对应操作和数据,action中的“android.intent.action.VIEW“在Intent文件中对应的就是ACTION_VIEW
Intent.java:
public static final String ACTION_VIEW = "android.intent.action.VIEW";
data部分我们定义了android:scheme的属性为http和https。这样intent-filter就能过滤请求为http和https的URI。
intent-filter的data子节点的子元素和特性包括:host、mimeType、path、pathPattern、pathPrefix、port、scheme。具体每种的意义可以参考android官网。
mimeType类型是一个经常用到的类型。例如:我们可以查看一组笔记:
<intent-filter>
	<action android:name="android.intent.action.VIEW" />
	<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
<intent-filter>
也可以查看单个笔记
<intent-filter>
	<action android:name="android.intent.action.VIEW" />
	<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
<intent-filter>

3.使用extra信息

除了操作和数据外,intent还包含extra额外信息,extra可以向intent提供更多的信息。extra以键值对的形式表示,键名称通常是以包名开头,值可以是任何基本的数据类型或任意对象,只要他实现了andorid.os.pracelable接口即可。extra使用andorid.os.bundle表示。
可以使用以下方法访问extra bundle
// Get the Bundle from an 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(anotherBudnle);
我们可以使用以下方法向extra添加数据:
putExtra(String name, boolean value);
putExtra(String name, int value);
putExtra(String name, double value);
putExtra(String name, String value);
putExtra(String name, int[] values);
putExtra(String name, float[] values);
putExtra(String name, Serializable value);
putExtra(String name, Parcelable value);
putExtra(String name, Bundle value);
putExtra(String name, Intent anotherIntent);
putIntegerArrayListExtra(String name, ArrayList arrayList);
putParcelableArrayListExtra(String name, ArrayList arrayList);
putStringArrayListExtra(String name, ArrayList arrayList);

4.使用组件直接调用活动

我们可以直接指定Activity的ComponentName来访问Activity。具体如下:
setComponent(ComponentName name);
setClassName(String packageName, String classNameInThatPackage);
setClassName(Context context, String classNameInThatContext);
setClass(Context context, Class classObjectInThatContext);
ComponentName将一个包名和类名包装在一起。例如,以下代码调用系统contacts活动:
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.andorid.contacts", "com.android.aontacts.DialContactsEntryActivity"));
startActivity(intent);
也可以直接使用类名,不构造ComponentName,例如:
Intent directIntent = new Intent(activity, BasicViewActivity.class);
activity.start(directIntent);
别忘记,在AndroidManifest.xml中注册Activity
<activity android:name=".BasicViewActivity"
	android:label="Test Activity">
这里我们不需要intent-filter,因为这种类型的Intent是显式Intent,显式Intent指定了一个完全限定的Android组件,所以会忽略掉该Intent的其他部分。

5.Intent类别

可以将活动分为不同的类别,以便根据类别名来搜索。比如,我们定义一个启动页面:
<activity
<span style="white-space:pre">	</span>android:name=".MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>
其中android.intent.category.LAUNCHER则将这个页面定义为启动页面。
更多类别可以访问android官网查看: http://developer.android.com/intl/zh-cn/reference/android/content/Intent.html
之后我们就可以使用一下代码进行访问:
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.adCategory(Intent.CATEGORY_LAUNCHER);
PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
借助于PackagerManager就可以找到与Intent相匹配的活动。

6.Intent解析规则

Android使用多种策略,基于Intent过滤器来将Intent和他们的目标活动相匹配。Intent分为显式和隐式。如果设置了名称,则这个Intent就是显式Intent,对于显式Intent,重要的是组件名称,Intent的所有其他方面或者特性都会被忽略。如果没有指定名称的Intent就是隐式Intent,解析隐式Intent目标的规则非常多。
基本规则是,传的Intent的操作,类别和数据特征必须匹配Intent过滤器中指定的特征。与Intent不同,一个Intent过滤器可以指定多个操作,类别和数据特征。这意味着一个Intent过滤器可以满足多个Intent的需求,也就是说一个活动响应多个Intent。但是,“匹配”的含义在操作,数据特征和类别之间各不相同。我们看看隐式Intent的每部分匹配条件。
1.操作
如果Intent有一个操作,Intent过滤器必须将这个操作添加到操作列表,或者不包含任何操作。如果Intent过滤器没有定义任何操作,则该Intent过滤器可以匹配所有传入的Intent操作。相应,如果Intent过滤器中定义了一个或多个操作,则至少一个操作与传入的Intent操作匹配。
2.数据
如果Intent中没有指定数据类型,他将不匹配包含任何数据或者数据特征的传入的Intent,他将仅查找没有指定数据类型的Intent。
在过滤器中,缺少数据和缺少操作的情况是相反的。如果过滤器没有操作,将匹配所有内容。如果过滤器中没有数据,将都不匹配。
3.数据类型
要匹配一种数据类型,传入Intent的数据类型必须是Intent过滤器中指定的数据类型之一。Intent中的数据类型必须存在于Intent过滤器中。
传入Intent的数据类型可以通过以下两种方式来确定。第一种:如果数据URI是一个内容或者文件URI,ContentProvider或者Android将确定类型。第二种:查看 Intent的显式数据类型,这种方式要生效,传入的Intent不应该设置数据URI,因为当对Intent调用setType()是会自动设置他。
作为MIME类型范围的一部分,Android还支持使用星号(*)作为子类型来涵盖所有可能的子类型。
4.数据模式
要匹配数据模式,传入Intent的数据模式必须是Intent过滤器中的指定的模式之一,换句话说,传入的数据模式必须存在于Intent过滤器中。
5.数据授权
如果过滤器中没有数据授权,则可以匹配任何传入的数据URI的授权,如果在过滤器中指定了授权,那么一种模式和授权应该与传入的Intent的数据URI想匹配。
6.数据路径
如果过滤器中没有数据路径,则可以匹配任何传入的数据URI的路径,如果在过滤器中指定了路径,那么一种模式,授权和路径应该与传入的Intent的数据URI想匹配。
换句话说,模式,授权和路径协同验证传入Intent的URI,所以path、authority和scheme不是孤立工作的,而是协同工作的。






























猜你喜欢

转载自blog.csdn.net/Ithink213/article/details/46891031