一、启动初探
【要看Launcher如何启动桌面上的app的同学,请绕行,非本篇内容】
”在android手机上,当我们点击桌面上的按钮启动一个应用,就能打开应用的界面。这里我们所说的桌面其实就是android系统启动后的就已经帮我们运行的第一个程序,launcher程序。
launcher程序可以理解为作为其它应用app入口管理的一个系统自带的app,正常情况下,安装一个新的应用,就会在桌面(laucher)程序中显示一个相应的图标。
上述点击桌面上的图标打开应用的过程,本质上是通过lancher应用的提供的桌面图标启动另一个app的过程,并打开了新应用的首个Activity。
我们自己是否能开发这样的一个自定义桌面程序呢,其实是可以的。
二、Android提供的launcherActivity源码分析(基于Android10.0源码)
桌面程序就是我们平常所说的launcher程序,我们在手机桌面上看到的应用的icon,实际上是在LauncherActivity上实现的。接下来我们看launcherActivity的源代码:
public abstract class LauncherActivity extends ListActivity {Intent mIntent;PackageManager mPackageManager;IconResizer mIconResizer;.....@Overrideprotected void onListItemClick(ListView l, View v, int position, long id) {Intent intent = intentForPosition(position);startActivity(intent);}...}
《基于android10.0源码分析Activity的启动流程》在之前写过这篇文章中,我们就是从StartActivity入手,分析了启动Activity的源码实现流程。
对于从桌面启动一个Activity本质上也是构建了一个intent去调用startActivity(intent)。这里面我们再看一下intentForPosition(position)的源码,来确定我们的intent构建是大概是如何关联到我们的我们平常在开发自己的应用的时候设置的launcher activity。
/*** 返回指定位置所对应的app的真实intent*/
protected Intent intentForPosition(int position) {ActivityAdapter adapter = (ActivityAdapter) mAdapter;return adapter.intentForPosition(position);
}
实际上继续调用了LaucherActivity的内容类ActivityAdapter的intentForPosition()
private class ActivityAdapter extends BaseAdapter implements Filterable {public Intent intentForPosition(int position) {if (mActivitiesList == null) {return null;}Intent intent = new Intent(mIntent);ListItem item = mActivitiesList.get(position);intent.setClassName(item.packageName, item.className);if (item.extras != null) {intent.putExtras(item.extras);}return intent;}
}
当前要执行的Activity的确定是在mActivitiesList获取的。看一下mActivitiesList的存储的内容:
private class ActivityAdapter extends BaseAdapter implements Filterable {...... public ActivityAdapter(IconResizer resizer) {mIconResizer = resizer;mInflater = (LayoutInflater) LauncherActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);mShowIcons = onEvaluateShowIcons();mActivitiesList = makeListItems();}
}
接着看makeListItems()
public List<ListItem> makeListItems() {List<ResolveInfo> list &#61; onQueryPackageManager(mIntent);onSortResultList(list);ArrayList<ListItem> result &#61; new ArrayList<ListItem>(list.size());int listSize &#61; list.size();for (int i &#61; 0; i < listSize; i&#43;&#43;) {ResolveInfo resolveInfo &#61; list.get(i);result.add(new ListItem(mPackageManager, resolveInfo, null));}return result;
}
这里面&#xff0c;我们看到实际的ActivitiesList是通过PackageManager加载得到&#xff0c;getPackageManager实现是在contextImpl.java中实现&#xff0c;通过下载android的framework层的源码关联找到&#xff0c;刚开始在android studio中直接关联是找不到具体的方法实现。
&#64;Override
public PackageManager getPackageManager() {if (mPackageManager !&#61; null) {return mPackageManager;}IPackageManager pm &#61; ActivityThread.getPackageManager();if (pm !&#61; null) {return (mPackageManager &#61; new ApplicationPackageManager(this, pm));}return null;
}
上面的有些跑偏了&#xff0c;回到桌面上点击一个应用icon启动应用的流程上来&#xff0c;其实源码流程还是非常简单的&#xff1a;
1.通过PackageManager检索以mIntent为筛选条件的ResolveInfo集合
List<ResolveInfo> list &#61; onQueryPackageManager(mIntent);
2.对ResolveInfo集合二次封装成ListItem集合&#xff0c;成为列表Adapter的数据
3.当点击条目时&#xff0c;通过ListItem创建出跳转Intent&#xff0c;调用startActivity跳转
Intent intent &#61; intentForPosition(position);
startActivity(intent);
看完了这laucherActivity的源码&#xff0c;我们只要实现一个类继承此类&#xff0c;并改变getTargetIntent的实现。