LaucherActivity的源码分析和应用(非launcher桌面应用)

Posted hymKing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LaucherActivity的源码分析和应用(非launcher桌面应用)相关的知识,希望对你有一定的参考价值。

一、启动初探

【要看Launcher如何启动桌面上的app的同学,请绕行,非本篇内容】
”在android手机上,当我们点击桌面上的按钮启动一个应用,就能打开应用的界面。这里我们所说的桌面其实就是android系统启动后的就已经帮我们运行的第一个程序,launcher程序。

launcher程序可以理解为作为其它应用app入口管理的一个系统自带的app,正常情况下,安装一个新的应用,就会在桌面(laucher)程序中显示一个相应的图标。

上述点击桌面上的图标打开应用的过程,本质上是通过lancher应用的提供的桌面图标启动另一个app的过程,并打开了新应用的首个Activity。

我们自己是否能开发这样的一个自定义桌面程序呢,其实是可以的。

二、Android提供的launcherActivity源码分析(基于Android10.0源码)

桌面程序就是我们平常所说的launcher程序,我们在手机桌面上看到的应用的icon,实际上是在LauncherActivity上实现的。接下来我们看launcherActivity的源代码:

/**
 * Displays a list of all activities which can be performed
 * for a given intent. Launches when clicked.
 * 翻译:显示所有通过给定的intent能被执行的Activity列表。点击的时候启动
 */
public abstract class LauncherActivity extends ListActivity 
    Intent mIntent;
    PackageManager mPackageManager;//包管理器
    IconResizer mIconResizer;
  .....
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) 
    		//此处就是桌面图标被点击后,执行的核心代码
        Intent intent = intentForPosition(position);
        //调用了是Activity的startActivity方法
        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;
            
						// 通过mIntent构建了intent
            Intent intent = new Intent(mIntent);
    				// 获取确定位置的activity是谁
            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() 
    // Load all matching activities and sort correctly
    List<ResolveInfo> list = onQueryPackageManager(mIntent);
    onSortResultList(list);

    ArrayList<ListItem> result = new ArrayList<ListItem>(list.size());
    int listSize = list.size();
    for (int i = 0; i < listSize; i++) 
        ResolveInfo resolveInfo = list.get(i);
        result.add(new ListItem(mPackageManager, resolveInfo, null));
    

    return result;

这里面,我们看到实际的ActivitiesList是通过PackageManager加载得到,getPackageManager实现是在contextImpl.java中实现,通过下载android的framework层的源码关联找到,刚开始在android studio中直接关联是找不到具体的方法实现。

@Override
public PackageManager getPackageManager() 
    if (mPackageManager != null) 
        return mPackageManager;
    
		//非常熟悉的ActivityThread,后续的源码实现,我们能看到类似Ams的binder的接口
    //这里也是跨进程的通信
    IPackageManager pm = ActivityThread.getPackageManager();
    if (pm != null) 
        // Doesn't matter if we make more than one instance.
        return (mPackageManager = new ApplicationPackageManager(this, pm));
    

    return null;

上面的有些跑偏了,回到桌面上点击一个应用icon启动应用的流程上来,其实源码流程还是非常简单的:

1.通过PackageManager检索以mIntent为筛选条件的ResolveInfo集合

List<ResolveInfo> list = onQueryPackageManager(mIntent);

2.对ResolveInfo集合二次封装成ListItem集合,成为列表Adapter的数据

3.当点击条目时,通过ListItem创建出跳转Intent,调用startActivity跳转

Intent intent = intentForPosition(position);
startActivity(intent);

看完了这laucherActivity的源码,我们只要实现一个类继承此类,并改变getTargetIntent的实现。

以上是关于LaucherActivity的源码分析和应用(非launcher桌面应用)的主要内容,如果未能解决你的问题,请参考以下文章

并发编程 —— 源码分析公平锁和非公平锁

JUC源码分析-集合篇ConcurrentLinkedQueue

源码HashMap源码及线程非安全分析

Spring源码分析(二十四)初始化非延迟加载单例

Spring源码分析非懒加载的Bean实例化过程(下篇)

源码分析:①ReentrantLock之公平锁和非公平锁