深入学习Intent和任务

使用隐式Intent,创建一个启动器应用来替换Android默认的启动器应用。

一、解析隐式intent

MAIN/LAUNCHER intent过滤器可能无法与通过startActivity(…)方法发送的MAIN/LAUNCHER隐式intent相匹配。

实际上,调用startActivity(intent)方法意味着“启动与发送的隐式intent相匹配的默认activity”,而不是想当然的“启动与发送的隐式intent相匹配的activity”。调用startActivity(intent)方法(或调用startActivityForResult(…)方法)发送隐式intent时,操作系统会悄然地将Intent.CATEGORY_DEFAULT类别添加给目标intent。

因而,如果希望一个intent过滤器能够与通过startActivity(intent)方法发送的隐式intent相匹配,那么必须在对应的intent过滤器中包含DEFAULT类别。

定义了MAIN/LAUNCHER intent过滤器的activity是应用的主要入口点。它只关心作为应用主要入口点处理的工作。它通常不关心自己是否属于默认的主要入口点,因此,它不必包含CATEGORY_DEFAULT类别。

MAIN/LAUNCHER intent过滤器并不一定包含CATEGORY_DEFAULT类别,因此,是否可以与通过startActivity(intent)方法发送的隐式intent相匹配,谁也说不准。所以,我们转而使用intent直接向PackageManager查询具有MAIN/LAUNCHER intent过滤器的activity。

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent startupIntent = new Intent(Intent.ACTION_MAIN);
        startupIntent.addCategory(Intent.CATEGORY_LAUNCHER);

        PackageManager pm = getActivity().getPackageManager();
        List<ResolveInfo> activities = pm.queryIntentActivities(startupIntent,
                0);

        /**
         * activity标签即用户可以识别的显示名称。既然查到的activity都是启动activity,标签名通常也就是应用名。
         * 按activity标签的字母顺序进行排序。
         */
        Collections.sort(activities, new Comparator<ResolveInfo>() {

            @Override
            public int compare(ResolveInfo lhs, ResolveInfo rhs) {
                PackageManager pm = getActivity().getPackageManager();
                return String.CASE_INSENSITIVE_ORDER.compare(lhs.loadLabel(pm)
                        .toString(), rhs.loadLabel(pm).toString());
            }
        });

        ArrayAdapter<ResolveInfo> adapter = new ArrayAdapter<ResolveInfo>(
                getActivity(), android.R.layout.simple_list_item_1, activities) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View view = super.getView(position, convertView, parent);
                PackageManager pm = getActivity().getPackageManager();
                TextView tv = (TextView) view;
                ResolveInfo resolveInfo = getItem(position);
                tv.setText(resolveInfo.loadLabel(pm));
                return view;
            }
        };

        setListAdapter(adapter);
    }

二、在运行时创建显式intent

使用ActivityInfo对象中的数据信息,创建一个显式intent并启动目标activity。

@Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        ResolveInfo resolveInfo = (ResolveInfo) l.getAdapter().getItem(position);
        ActivityInfo activityInfo = resolveInfo.activityInfo;

        if(activityInfo == null) return;

        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setClassName(activityInfo.applicationInfo.packageName, activityInfo.name);
        /**
         * 在新任务中启动activity(任务即activity栈)
         * FLAG_ACTIVITY_NEW_TASK标志控制着每个activity仅创建一个任务。
         */
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

从以上代码可以看到,作为显式intent的一部分,我们还发送了ACTION_MAIN操作。发送的intent是否包含操作,对于大多数应用来说没有什么差别。不过,有些应用的启动行为可能会有所不同。取决于不同的启动要求,同样的activity可能会显示不同的用户界面。开发人员最好能明确启动意图,以便让activity完成它应该完成的任务。

在上述代码中,使用获取的包名与类名创建一个显式intent时,我们使用了以下方法:

Public Intent  setClassName(String packageName, String className)

这不同于以往创建显式intent的方式。在这之前,我们都是使用一个接受Content和Class对象的Intent构造方法:

Public Intent  (Context packageContext , Class<?> cls)

该构造方法使用传入的参数来获取Intent需要的ComponentName。ComponentName由包名和类名共同组成。传入Activity和Class创建Intent时,构造方法会通过Activity类自行确定全路径包名。

也可以自己通过包名和类名创建一个ComponentName,然后使用下面的Intent方法创建一个显式intent

Public Intent  setComponent(ComponentName component)

三、使用当前应用作为设备主屏幕

<activity
            android:name="com.example.nerdlauncher.NerdLauncherActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
                <!--通过添加HOME与DEFAULT类别定义,该应用的activity会成为可选的主界面。点击Home键,可以选择。  -->
            </intent-filter>
        </activity>

四、应用图标与任务重排

ResolveInfo类还提供了另一个名为loadIcon(…)的方法。可以使用该方法为每一个应用加载显示图标。

使用Activity.ACTIVITY_SERVICE常量调用Activity.getSystemService()方法,来获取ActivityManager。然后调用ActivityManager的getRunningTasks()方法,得到按运行时间由近及早排序的运行任务列表。再调用moveTaskToFront()方法实现将任意任务切换到前台。最后,要提醒的是,关于任务间的切换,还需要在配置文件中增加其他权限配置。

五、进程与任务

每一个activity实例都仅存在于一个进程和一个任务中。这也是进程与任务的唯一类似的地方。任务只包含activity,这些activity通常来自于不同应用。而进程则包含了应用的全部运行代码和对象。

activity赖以生存的进程与任务有可能不同。例如,在A应用中启动B应用(不开启新任务)。虽然B应用是在A应用任务中启动的,但它是在B应用的进程中运行的。

Android无法终止任务或替换Android默认的任务管理器,我们只能终止进程。

代码地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值