Android launcher应用的简单实现

来源:互联网 发布:有机合成工艺优化理由 编辑:程序博客网 时间:2024/05/29 07:10

本篇文章将实现一个简单的可替代系统桌面的launcher应用。
此应用应该具有如下功能:
1. 自定义的桌面应用能够被设置为系统的默认桌面,替代原有桌面。
2. 系统桌面上的app图标能够排列在我们的自定义桌面上。
3. 点击自定义桌面上的app图标,能够打开对应的app。

下面就看看具体实现:
新建一个空项目,命名为LauncherTest,然后打开项目的manifest文件:
一般情况下,自动生成的MainActivity的配置如下:

        <activity android:name=".MainActivity" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>

其中”android.intent.action.MAIN”这个action指定了应用的入口activity,”android.intent.category.LAUNCHER”指定了程序的图标要显示在应用程序列表里。

一、功能一

要实现功能一,要对上面的代码intent-filter里加上如下两行:

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

如果此桌面activity不需要另外显示图标在系统桌面上的话,就不需要category android:name=”android.intent.category.LAUNCHER”这行。
这样的话,我们的程序运行起来后,再按手机Home键时,系统就会弹出一个列表,列出所有的桌面应用,让用户选择用哪个应用打开桌面。里面就会包含我们的LauncherTest。

但是我们的应用什么功能都没有,即使选为桌面也是任何功能都没有的。

二、功能二:

要怎么列出系统桌面上显示的所有的app的图标呢?
我们可以先获取对应的app列表,然后逐个获取并显示其图标。实现如下:

    //系统桌面上显示的app列表    private List<ResolveInfo> localApps;

在MainActivity的onCreate()里调用如下得到app列表信息:

        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);        localApps = getPackageManager().queryIntentActivities(mainIntent, 0);

这些app图标里也会包含我们自己的应用图标,但理想效果应该是不显示比较好,因为我们的app是用来替代系统桌面的,没有别的作用。如果不显示自己的图标呢?加上以下的代码:

        //遍历获取的app列表,如果哪个元素的app包名和我们的一样,就说明是我们本应用,则移除此元素。        Iterator<ResolveInfo> iterator = localApps.iterator();        while(iterator.hasNext()) {            ResolveInfo resolveInfo = iterator.next();            String packageName = resolveInfo.activityInfo.packageName;            if(packageName.equals(getApplication().getPackageName())) {                iterator.remove();            }        }

在这里注意用到了iterator的remove()来移除List中的元素。那么用List类的remove()方法可以不?答案是不行,如果在List遍历的过程中用List的remove()方法删除List的元素,会发生CurrentModificationException。而Iterator的remove()方法是安全有效的,不会发生异常。

接下来,我们要获取每个app的图标并显示出来,显示图标可以用到GridView,用以把图标网格状显示,和系统桌面效果一样。
修改布局文件activity_main.xml, 加入GridView:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@android:color/darker_gray">    <GridView        android:id="@+id/apps_list"        android:layout_width="match_parent"        android:numColumns="4"        android:gravity="center"        android:verticalSpacing="20dp"        android:paddingTop="10dp"        android:paddingBottom="10dp"        android:scrollbars="none"        android:overScrollMode="never"        android:layout_height="wrap_content">    </GridView></RelativeLayout>

其中有几个属性说一下:
android:numColumns=”4”是设置图标列数为4。
android:verticalSpacing=”20dp”是设置每行之间的间距。
android:scrollbars=”none”是为了去掉列表滑动时右边的滚动条。
android:overScrollMode=”never”是为了去掉列表下拉或者上拉时,顶部或底部出现的半月形的阴影。

然后看看MainActivity中怎么使用:
我们需要给GridView设置一个适配器,然后需要给app图标的显示定义一个布局:

app图标显示的布局如下:
icon_layout.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:orientation="vertical"    android:gravity="center_horizontal"    android:layout_width="match_parent"    android:layout_height="wrap_content">    <ImageView        android:id="@+id/app_icon"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        tools:src ="@mipmap/ic_launcher"/>    <TextView        android:id="@+id/app_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        tools:text="相机"/></LinearLayout>

显示的效果就是上面一个图标,下面一个app名。

然后下面是对应的适配器的定义:

    public class AppsAdapter extends BaseAdapter {        private List<ResolveInfo> apps;        //构造器中传入app列表信息        public AppsAdapter(List<ResolveInfo> apps){            this.apps = apps;        }        @Override        public int getCount() {            return apps.size();        }        @Override        public Object getItem(int i) {            return apps.get(i);        }        @Override        public long getItemId(int i) {            return i;        }        @Override        public View getView(int i, View view, ViewGroup viewGroup) {            //为了简单起见,这里没有用ViewHolder,可以改成ViewHolder以改善显示效率            LayoutInflater inflater = LayoutInflater.from(MainActivity.this);            View appView = inflater.inflate(R.layout.icon_layout, null);            ImageView iv = (ImageView) appView.findViewById(R.id.app_icon);            //设置图标适应方式和大小                                   iv.setScaleType(ImageView.ScaleType.FIT_CENTER);            iv.setLayoutParams(new LinearLayout.LayoutParams(70, 70));            TextView tv = (TextView) appView.findViewById(R.id.app_name);            ResolveInfo info = apps.get(i);            //显示app图标                iv.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));            //显示app名            String appName = info.loadLabel(getPackageManager()).toString();            tv.setText(appName);            return appView;        }    }

上面的代码里,getView方法每次都会创建一个新的view,当数据很多时,显示效率会很低。优化方案点这里ViewHolder优化显示性能
然后设置此适配器为GridView的适配器:

        GridView appsGrid = (GridView) findViewById(R.id.apps_list);        appsGrid.setAdapter(new AppsAdapter(localApps));

自此,第二个功能就完成了,app列表已经可以完全显示在我们的app界面上了。

三、功能三

第三个功能,点击各个app图标启动对应的app。
下面是点击事件的代码:

    private AdapterView.OnItemClickListener clickListener = new AdapterView.OnItemClickListener() {        @Override        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {            ResolveInfo info = localApps.get(i);            //该应用的包名            String pkg = info.activityInfo.packageName;            //应用的主activity类            String cls = info.activityInfo.name;            ComponentName componet = new ComponentName(pkg, cls);            //打开该应用的主activity            Intent intent = new Intent();            intent.setComponent(componet);            startActivity(intent);        }    };

然后把点击事件应用到GridView上:

appsGrid.setOnItemClickListener(clickListener);

这样第三个功能也就完成了。

至此一个简单的桌面应用就完成了。效果图如下:

原创粉丝点击