如何在Android上開發(fā)屬于自己的定制化啟動器
譯文【51CTO譯文】我們要開發(fā)的就是這樣一套方案。
介紹
從最基本的概念角度來講,啟動器其實應(yīng)該是一款能夠?qū)崿F(xiàn)以下功能的應(yīng)用程序:
- 它代表著一臺設(shè)備的主屏幕。
- 它能夠列出并啟動已經(jīng)安裝在該設(shè)備當中的應(yīng)用程序。
換句話來說,它就是那款用戶按下home按鈕后所顯示的應(yīng)用程序。除非大家已經(jīng)安裝了定制化啟動器,否則我們目前正在使用的應(yīng)該都是Android系統(tǒng)自帶的默認啟動方案。不少設(shè)備制造商都會在產(chǎn)品中默認使用由其定制的啟動器,從而確保我們獲得與廠商預(yù)期相符的外觀效果與使用感受,例如三星TouchWiz以及HTC Sense。
在今天的教程中,我們將利用基本用戶界面創(chuàng)建出一款簡單的啟動器,它將由兩部分屏幕構(gòu)成:
- 在主屏幕中顯示的是該設(shè)備的墻紙圖案。
- 另一屏幕中顯示的是已經(jīng)安裝在設(shè)備當中的應(yīng)用程序圖標及其它細節(jié)信息。
1.要求
大家需要在自己的開發(fā)設(shè)備上預(yù)先安裝并配置好以下項目:
- Android SDK以及平臺工具
- Eclipse IDE 3.7.2或者更高版本,同時具備ADT插件
- 運行有Android 2.2或者更高版本的模擬器或者Android設(shè)備
大家可以點擊此處通過Android開發(fā)者門戶下載對應(yīng)SDK及平臺工具。
2.項目設(shè)置
首先我們需要啟動Eclipse并創(chuàng)建一個新的Android應(yīng)用程序項目。我為這個應(yīng)用取了個非常直白的名稱——SimpleLauncher,當然大家也可以自由選擇自己想要的名稱。請確保軟件包名稱沒有與其它項目出現(xiàn)重復(fù)。我們的啟動器所能支持的***SDK版本為“凍酸奶”,而主要的面向版本則為“果凍豆”。
由于我們不打算創(chuàng)建Activity,因此取消“Create Activity”勾選項,然后點擊“Finish”以繼續(xù)。
3.項目清單
接下來我們需要通過添加兩個activity對AndroidManifest.xml文件進行修改。***個Activity用于顯示主屏幕,我們?nèi)缦滤緦⑵涿麨镠omeActivity。
- <activity
- android:name="ah.hathi.simplelauncher.HomeActivity"
- android:label="Simple Launcher Home"
- android:theme="@android:style/Theme.Wallpaper.NoTitleBar.Fullscreen"
- android:launchMode="singleTask"
- android:stateNotNeeded="true"
- >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.HOME" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
通過將android.intent.category.HOME與android.intent.category.DEFAULT兩個類添加至intent-filter組當中,相關(guān)Activity得以擁有與啟動器概念相符的運行方式。當大家按下設(shè)備上的home按鈕時,其還將作為選項方案顯示出來。
我們還需要將launchMode設(shè)置到singleTask當中,從而確保無論何時都只有單一Activity實例由系統(tǒng)負責運行。要顯示用戶的墻紙圖案,大家必須將主題設(shè)置為Theme.Wallpaper.NoTitleBar.FullScreen。
我們需要添加的第二個Activity負責顯示已經(jīng)安裝在用戶設(shè)備中的應(yīng)用程序條目。它還有另一項任務(wù),即啟動這些應(yīng)用程序。我們不需要對該Activity進行任何特殊配置,將其命名為AppsListActivity即可。
- <activity
- android:name="ah.hathi.simplelauncher.AppsListActivity"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- >
- </activity>
4.Activity布局
下面在項目的res/layout文件夾中為HomeActivity類創(chuàng)建一個XML文件,并將其命名為activity_home.xml。該布局擁有一個單獨的Button用以響應(yīng)點觸事件。點觸該按鈕能夠讓用戶由主屏幕切換至應(yīng)用程序列表。
- <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"
- tools:context=".HomeActivity" >
- <Button
- android:id="@+id/apps_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_marginRight="10dp"
- android:layout_marginTop="10dp"
- android:text="Show Apps"
- android:onClick="showApps"
- />
- </RelativeLayout>
接下來,在項目的res/layout文件夾中為AppsListActivity類創(chuàng)建一個XML文件并將其命名為activity_apps_list.xml。該布局當中包含一個占據(jù)整個屏幕的ListView。
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
- <ListView
- android:id="@+id/apps_list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- </ListView>
- </LinearLayout>
***,在同樣的位置創(chuàng)建第三個XML文件并將其命名為list_item.xml。該文件用于定義ListView當中各個條目的布局方案。列表視圖中的每個條目都代表著已經(jīng)安裝在用戶設(shè)備上的一款應(yīng)用程序。它能夠顯示該應(yīng)用程序的圖標、標簽以及軟件包名稱。我們可以利用ImageView實例來顯示該應(yīng)用的圖標,并通過TextView實例顯示標簽與軟件包名稱。
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="10dp"
- >
- <ImageView
- android:id="@+id/item_app_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- />
- <TextView
- android:id="@+id/item_app_label"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@+id/item_app_icon"
- android:paddingLeft="10dp"
- />
- <TextView
- android:id="@+id/item_app_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/item_app_label"
- android:layout_toRightOf="@+id/item_app_icon"
- android:paddingLeft="10dp"
- />
- </RelativeLayout>
5.創(chuàng)建Acitivity類
HomeActivity
應(yīng)用程序的布局方案創(chuàng)建完成之后,現(xiàn)在要做的是創(chuàng)建兩個Activity類。當創(chuàng)建這兩個類時,請確保每個類的名稱都與我們之前在項目清單文件中所指定的內(nèi)容相匹配。
創(chuàng)建一個名為HomeActivity的新類,然后將android.app.Activity設(shè)置為其超類。
- package ah.hathi.simplelauncher;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- public class HomeActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_home);
- }
- public void showApps(View v){
- Intent i = new Intent(this, AppsListActivity.class);
- startActivity(i);
- }
- }
在該類的onCreate方法中,我們調(diào)用setContentView并將其傳遞至之前已經(jīng)創(chuàng)建完成的布局當中。大家可能還記得,我們曾為activity_home布局添加過一個按鈕,用于觸發(fā)名為showApps的方法。現(xiàn)在我們要做的是將該方法引入HomeActivity類當中。整個添加過程非常簡單,各位需要做的只是為AppsListActivity類創(chuàng)建一個Intent并付諸運行。
#p#
AppsListActivity
創(chuàng)建另一個名為AppsListActivity的Activity類,而后將android.app.Activity設(shè)置為其超類。在該類的onCreate方法當中,我們調(diào)用setContentView并將其傳遞至此前已經(jīng)創(chuàng)建完成的activity_apps_list布局當中。
- package ah.hathi.simplelauncher;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- public class AppsListActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_apps_list);
- }
- }
雖然我們的啟動器方案還沒有最終完成,但到這里大家已經(jīng)可以保存現(xiàn)有內(nèi)容并借此啟動自己設(shè)備上的應(yīng)用程序了。當各位按下設(shè)備上的home按鈕時,系統(tǒng)會能夠彈窗詢問我們希望使用哪種啟動器方案。
如果大家選擇了Simple Launcher Home,則可以看到自己創(chuàng)建的全新主屏幕,其右上屏幕位置還配備一個按鈕。大家還能看到自己設(shè)備上原本設(shè)定的墻紙圖案。
現(xiàn)在回到Eclipse并創(chuàng)建一個名為AppDetail的類,其中將包含與應(yīng)用程序相關(guān)的細節(jié)信息、軟件包名稱、標簽以及應(yīng)用程序圖標。該界面非?;A(chǔ),大家可以利用如下代碼實現(xiàn):
- package ah.hathi.simplelauncher;
- import android.graphics.drawable.Drawable;
- public class AppDetail {
- CharSequence label;
- CharSequence name;
- Drawable icon;
- }
6.獲取應(yīng)用程序
在AppsListActivity類的loadApps方法當中,我們可以使用PackageManager類的queryIntentActivities方法以獲取Intent.CATEGORY_LAUNCHER類別當中的所有Intents。該查詢能夠返回一份列表,其中包含全部能夠經(jīng)由啟動器實現(xiàn)啟動的應(yīng)用程序。我們可以將查詢返回結(jié)果中的每個條目添加到名為apps的列表當中。大家可以通過以下代碼片段進一步了解其效果。
- private PackageManager manager;
- private List<AppDetail> apps;
- private void loadApps(){
- manager = getPackageManager();
- apps = new ArrayList<AppDetail>();
- Intent i = new Intent(Intent.ACTION_MAIN, null);
- i.addCategory(Intent.CATEGORY_LAUNCHER);
- List<ResolveInfo> availableActivities = manager.queryIntentActivities(i, 0);
- for(ResolveInfo ri:availableActivities){
- AppDetail app = new AppDetail();
- app.label = ri.loadLabel(manager);
- app.name = ri.activityInfo.packageName;
- app.icon = ri.activityInfo.loadIcon(manager);
- apps.add(app);
- }
- }
7.顯示應(yīng)用程序列表
由于apps變量當中包含有我們所需要的全部細節(jié)信息,因此大家可以利用ListView類顯示出完整的應(yīng)用程序列表。我們首先創(chuàng)建一個簡單的ArrayAdapter并覆蓋其getView方法以獲取列表中的條目信息。接下來,將該ListView與適配器相關(guān)聯(lián)。
- private ListView list;
- private void loadListView(){
- list = (ListView)findViewById(R.id.apps_list);
- ArrayAdapter<AppDetail> adapter = new ArrayAdapter<AppDetail>(this,
- R.layout.list_item,
- apps) {
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if(convertView == null){
- convertView = getLayoutInflater().inflate(R.layout.list_item, null);
- }
- ImageView appIcon = (ImageView)convertView.findViewById(R.id.item_app_icon);
- appIcon.setImageDrawable(apps.get(position).icon);
- TextView appLabel = (TextView)convertView.findViewById(R.id.item_app_label);
- appLabel.setText(apps.get(position).label);
- TextView appName = (TextView)convertView.findViewById(R.id.item_app_name);
- appName.setText(apps.get(position).name);
- return convertView;
- }
- };
- list.setAdapter(adapter);
- }
8.偵聽點觸操作
當用戶點觸ListView當中的某個條目時,我們的啟動器應(yīng)該能夠運行相應(yīng)的應(yīng)用程序。我們可以通過PackageManager類中的getLaunchIntentForPackage方法來創(chuàng)建一個Intent,用于指定我們要啟動哪款應(yīng)用程序。請大家查看以下代碼片段。
- private void addClickListener(){
- list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> av, View v, int pos,
- long id) {
- Intent i = manager.getLaunchIntentForPackage(apps.get(pos).name.toString());
- AppsListActivity.this.startActivity(i);
- }
- });
- }
9.通過整合實現(xiàn)完整功能
為了讓前面提到的全部內(nèi)容整合起來并實現(xiàn)完整功能,我們需要在AppsListActivity類的onCreate方法中調(diào)用loadApps、loadListView與addClickListener,具體代碼如下所示。
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_apps_list);
- loadApps();
- loadListView();
- addClickListener();
- }
下面編譯并運行我們的啟動器應(yīng)用,并再一次運行以查看結(jié)果。大家現(xiàn)在應(yīng)該已經(jīng)能夠在啟動器主屏幕中點擊該按鈕后查看所有可以啟用的應(yīng)用程序了。別猶豫,快點觸其中一個嘗試一下吧。
總結(jié)
大家現(xiàn)在已經(jīng)擁有自己的定制化啟動器了。它很簡單也很粗糙,但我們完全可以陸續(xù)為其添加更多功能特性、從而讓它逐步得到完善。如果大家想進一步了解能夠在啟動器中引入哪些自定義項目,我建議各位點擊此處查看Android開發(fā)者門戶當中給出的示例應(yīng)用程序。
原文鏈接:Build A Custom Launcher on Android
核子可樂譯