通过深度剖析Android之Launcher源码设计架构,创建HomeScreen的Shortcut(快捷方式)

应用场景:

        经常有这样的系统程序:当第一次使用系统时,退出系统后,我们会在手机桌面上发现刚刚使用过的系统图标,也就是系统自动创建了快捷方式到手机桌面,以供下次方便快捷的使用。当然,我们也完全可以自己去为他设置快捷方式,这个相信大家都会。

 

由此场景引出几个问题:

问题一:

         我们写程序的时候怎么样来实现类似的快捷方式创建呢?有哪些方式?

问题二:

         要实现此功能需要怎么样去设计?系统是否有现成的支持可以利用?(答案是肯定的)

问题三:

         如果系统支持刚功能的实现,我们就要去研究一下系统是怎么样去实现的,那应该怎么样下手去了解呢?

        

解决问题:

         思路:首先回顾我们经常使用手机创建快捷方式的方法得知,系统提供并支持各应用快捷方式的创建,创建方式可以有:在主屏幕(HomeScreen)空白处长按弹出对话框创建;在Launcher列表中长按某个应用程序创建。所以就可以看看android本身是怎么去实现该功能的。

         说明:HomeScreen本身是Launcher的一部分,所以归根结底还是Launcher的机制来创建快捷方式,所以就去分析Launcher的实现架构。

分析:

         创建项目导入Launcher包,该源码在AndroidSource_GB\packages\apps\Launcher2下,导入后打开mainfest.xml文件(入口文件),找到main函数入口,如一下代码:

  1. <activity  
  2.      android:name="com.android.launcher2.Launcher"  
  3.      android:launchMode="singleTask"  
  4.      android:clearTaskOnLaunch="true"  
  5.      android:stateNotNeeded="true"  
  6.      android:theme="@style/Theme"  
  7.      android:screenOrientation="nosensor"  
  8.      android:windowSoftInputMode="stateUnspecified|adjustPan">  
  9.      <intent-filter>  
  10.           <action android:name="android.intent.action.MAIN" />  
  11.           <category android:name="android.intent.category.HOME" />  
  12.           <category android:name="android.intent.category.DEFAULT" />  
  13.           <category android:name="android.intent.category.MONKEY"/>  
  14.      </intent-filter>  
  15. </activity>  
<activity
     android:name="com.android.launcher2.Launcher"
     android:launchMode="singleTask"
     android:clearTaskOnLaunch="true"
     android:stateNotNeeded="true"
     android:theme="@style/Theme"
     android:screenOrientation="nosensor"
     android:windowSoftInputMode="stateUnspecified|adjustPan">
     <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.HOME" />
          <category android:name="android.intent.category.DEFAULT" />
          <category android:name="android.intent.category.MONKEY"/>
     </intent-filter>
</activity>

        可以发现,跟原先我们熟悉的配置不一样的地方在于intent-filter中少了<category android:name="android.intent.category.LAUNCHER" />

原因很简单,他本身就是Launcher,所以不需要;但多了<category android:name="android.intent.category.HOME" />的配置,意思就是当点击home键后,回到主界面,也就是回到launcher,这验证了我上面所说的“HomeScreen本身是Launcher的一部分”。

         接下来打开Launcher.java,开始进入等待已久的Launcher源码分析。我们激动着……

 

         分析入口当然就是onCreate生命周期开始方法,如下代码所示:

  1. @Override  
  2. protected void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.   
  5.     LauncherApplication app = ((LauncherApplication)getApplication());  
  6.     mModel = app.setLauncher(this);  
  7.     mIconCache = app.getIconCache();  
  8.     mDragController = new DragController(this);//拖动控制对象,就是按着屏幕向左向右拖动,再如长按图标可以将图标拖到其他地方放置   
  9.     mInflater = getLayoutInflater();  
  10.   
  11.     mAppWidgetManager = AppWidgetManager.getInstance(this);  
  12.     mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);  
  13.     mAppWidgetHost.startListening();  
  14.   
  15.     if (PROFILE_STARTUP) {  
  16.         android.os.Debug.startMethodTracing(  
  17.                 Environment.getExternalStorageDirectory() + "/launcher");  
  18.     }  
  19.   
  20.     loadHotseats();  
  21.     checkForLocaleChange();//国际化语言发生变化的时候launcher也跟着变   
  22.     setWallpaperDimension();//设置图片尺寸大小   
  23.   
  24.     setContentView(R.layout.launcher);  
  25.     setupViews();  
  26.   
  27.     //注册上下文观察者,观察Content的数据变化   
  28.     /* 
  29.      * 实际上android架构存在这样的机制: 
  30.      * 用来观察ContentProvider里面的数据变化 
  31.      * 使用场景:当点击一个appwidget要添加到主界面显示的快捷方式时,实际上使用ContentProvider提供的insert方法,插了一条记录到数据库中 
  32.      * 然后利用该观察者模式去监听数据库值的改变,然后将改变的值从数据库读出来,更新到界面上来。 
  33.      */  
  34.     registerContentObservers();  
  35.   
  36.     lockAllApps();//锁定位置,不允许移动   
  37.   
  38.     mSavedState = savedInstanceState;  
  39.     restoreState(mSavedState);  
  40.   
  41.     if (PROFILE_STARTUP) {  
  42.         android.os.Debug.stopMethodTracing();  
  43.     }  
  44.   
  45.     if (!mRestoring) {  
  46.         mModel.startLoader(thistrue);  
  47.     }  
  48.   
  49.     // For handling default keys   
  50.     mDefaultKeySsb = new SpannableStringBuilder();  
  51.     Selection.setSelection(mDefaultKeySsb, 0);  
  52.   
  53.     IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);  
  54.     registerReceiver(mCloseSystemDialogsReceiver, filter);  
  55. }  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        LauncherApplication app = ((LauncherApplication)getApplication());
        mModel = app.setLauncher(this);
        mIconCache = app.getIconCache();
        mDragController = new DragController(this);//拖动控制对象,就是按着屏幕向左向右拖动,再如长按图标可以将图标拖到其他地方放置
        mInflater = getLayoutInflater();

        mAppWidgetManager = AppWidgetManager.getInstance(this);
        mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
        mAppWidgetHost.startListening();

        if (PROFILE_STARTUP) {
            android.os.Debug.startMethodTracing(
                    Environment.getExternalStorageDirectory() + "/launcher");
        }

        loadHotseats();
        checkForLocaleChange();//国际化语言发生变化的时候launcher也跟着变
        setWallpaperDimension();//设置图片尺寸大小

        setContentView(R.layout.launcher);
        setupViews();

        //注册上下文观察者,观察Content的数据变化
        /*
         * 实际上android架构存在这样的机制:
         * 用来观察ContentProvider里面的数据变化
         * 使用场景:当点击一个appwidget要添加到主界面显示的快捷方式时,实际上使用ContentProvider提供的insert方法,插了一条记录到数据库中
         * 然后利用该观察者模式去监听数据库值的改变,然后将改变的值从数据库读出来,更新到界面上来。
         */
        registerContentObservers();

        lockAllApps();//锁定位置,不允许移动

        mSavedState = savedInstanceState;
        restoreState(mSavedState);

        if (PROFILE_STARTUP) {
            android.os.Debug.stopMethodTracing();
        }

        if (!mRestoring) {
            mModel.startLoader(this, true);
        }

        // For handling default keys
        mDefaultKeySsb = new SpannableStringBuilder();
        Selection.setSelection(mDefaultKeySsb, 0);

        IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        registerReceiver(mCloseSystemDialogsReceiver, filter);
    }


        代码部分主要看解析的,其他的随便看看,主要是保持对launcher的不那么神秘感就OK,接下来看个截图:

 

分析图:

        该图就是launcher机制实现快捷方式创建的过程图,左边是长按屏幕弹出来的对话框,右边是点击左边“快捷方式”后跳转的图,即选择快捷方式图标。

分析该实现方式:

        一、 分析左图:该图从表面上看是一个dialog对话框,要实现该图就要实现Dialog接口,所以就到Launcher.java查找一下,结果是有的,自己去查找(CreateShortcut)。

        二、 分析右图:该图就是一个listview,将应用程序都列出来。问题是:系统怎么知道我的应用呢?是通过什么方式告诉他的呢?然后他就能将我们的应用列到这里。实际上是通过广播,在mainfest.xml配置广播,然后Launcher,让他去检索,所以我们只需要在我们的应用配置一下。后面会通过代码演示。

        说明:实际上你要跟踪Launcher的Dialog事件,进一步了解其实现机制,这里省去。提示pickShortcut(),该方法里面设置回调函数,通过setResult()的方式回传值。

 

        OK!居于以上的基础,我们就可以打造属于自己的应用程序的快捷方式创建了:

 

        实现创建快捷方式的两种方法:

        1:在主界面(HomeScreen)或者launcher中长按后,点击快捷方式添加

        2:在应用程序中某个操作中添加

 

        方式一:(分两步骤完成)

        首先在mianfest.xml注册

  1. <activity android:name=".ShortcutSampleActivity">  
  2.   
  3.     <intent-filter>  
  4.   
  5.         <action android:name="android.intent.action.CREATE_SHORTCUT"></action>  
  6.   
  7.     </intent-filter>  
  8.   
  9. </activity>  
<activity android:name=".ShortcutSampleActivity">

	<intent-filter>

		<action android:name="android.intent.action.CREATE_SHORTCUT"></action>

	</intent-filter>

</activity>

        说明:该注册代码是为了让长按后将自己的应用程序出现在列表中,如上图。

 

        其次在ShortcutSampleActivity.java中通过代码实现当点击了具体的某个应用程序后将图标创建到主界面中,生成快捷方式。

  1. public class ShortcutSampleActivity extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.   
  7.         // 将快捷方式显示在主界面中   
  8.         if (Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) {  
  9.             Intent intent = new Intent();  
  10.             intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "LeonShortcut");  
  11.             intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,  
  12.                     Intent.ShortcutIconResource.fromContext(this, R.drawable.icon));  
  13.             intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(this,  
  14.                     LeonLauncherDemoActivity.class));// 点击快捷方式跳转的页面   
  15.   
  16.             setResult(RESULT_OK, intent);// 设置返回值   
  17.               
  18.             finish();// 关窗体   
  19.         }  
  20.     }  
  21. }  
public class ShortcutSampleActivity extends Activity {

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

		// 将快捷方式显示在主界面中
		if (Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) {
			Intent intent = new Intent();
			intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "LeonShortcut");
			intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
					Intent.ShortcutIconResource.fromContext(this, R.drawable.icon));
			intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(this,
					LeonLauncherDemoActivity.class));// 点击快捷方式跳转的页面

			setResult(RESULT_OK, intent);// 设置返回值
			
			finish();// 关窗体
		}
	}
}


 

        方式二:(同样也是分两步骤完成)

        首先在mianfest.xml注册权限

        <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>

        说明:快捷方式广播指定权限

 

        其次通过按钮出发事件后实现快捷方式的创建,具体代码如下:

  1. public class LeonLauncherDemoActivity extends Activity {  
  2.   
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.main);  
  7.   
  8.         // 通过按钮直接添加快捷方式   
  9.         Button shortcutButton = (Button) this.findViewById(R.id.shortcut);  
  10.         shortcutButton.setOnClickListener(new OnClickListener() {  
  11.   
  12.             @Override  
  13.             public void onClick(View v) {  
  14.                 Intent intent = new Intent();  
  15.                 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "LeonShortcut");  
  16.                 intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,  
  17.                         Intent.ShortcutIconResource.fromContext(  
  18.                                 LeonLauncherDemoActivity.this, R.drawable.icon));  
  19.                 intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(  
  20.                         LeonLauncherDemoActivity.this,  
  21.                         LeonLauncherDemoActivity.class));// 点击快捷方式跳转的页面   
  22.   
  23.                 intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");  
  24.                   
  25.                 //通过广播的形式让launcher接收广播,然后根据action做出快捷方式的判断,从而系统自动创建快捷方式   
  26.                 sendBroadcast(intent);  
  27.             }  
  28.         });  
  29.     }  
  30. }  
public class LeonLauncherDemoActivity extends Activity {

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

		// 通过按钮直接添加快捷方式
		Button shortcutButton = (Button) this.findViewById(R.id.shortcut);
		shortcutButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent();
				intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "LeonShortcut");
				intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
						Intent.ShortcutIconResource.fromContext(
								LeonLauncherDemoActivity.this, R.drawable.icon));
				intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(
						LeonLauncherDemoActivity.this,
						LeonLauncherDemoActivity.class));// 点击快捷方式跳转的页面

				intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
				
				//通过广播的形式让launcher接收广播,然后根据action做出快捷方式的判断,从而系统自动创建快捷方式
				sendBroadcast(intent);
			}
		});
	}
}


        完成。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android LauncherAndroid系统上的一个应用程序,它是用户与系统交互的主要界面,也是用户启动应用程序的入口。它允许用户查看、操作和管理应用程序、小部件和系统功能。 Android Launcher源码解析涉及到多个关键组件和类。其中最重要的是LauncherActivity、PackageManager、AppWidgetManager和DesktopPane。 LauncherActivity是应用程序启动的入口点。它负责显示主屏幕和响应用户的触摸事件。在LauncherActivity中,使用了ViewPager来创建多个屏幕来容纳应用程序和小部件。 PackageManager是应用程序的管理器。通过PackageManager,Launcher可以获取系统中安装的应用程序信息、启动应用程序和监听应用程序的安装、卸载等事件。 AppWidgetManager用于管理应用程序的小部件。Launcher通过AppWidgetManager注册、更新和删除小部件。它还负责接收小部件的更新事件。 DesktopPane是主屏幕的容器。它使用GridLayout将应用程序和小部件布局在主屏幕上。DesktopPane还处理用户在主屏幕上的拖放操作,允许用户重新排序应用程序和小部件。 在源码解析过程中,还需要了解Android应用程序交互的一些核心概念,如Intent、Broadcast和Service等。Intent用于在组件之间传递消息,Broadcast用于传递系统事件,Service用于在后台执行任务。 在分析Launcher源码时,还需要关注性能优化和用户体验。例如,使用异步加载和缓存来提高应用程序和小部件的加载速度,使用动画效果来增强界面的流畅性。 综上所述,Android Launcher源码解析涉及多个组件和类,需要了解Android应用程序交互的核心概念,同时需要关注性能优化和用户体验。这个过程可以帮助开发者深入理解和定制Android系统的启动器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值