如何在Android上開發(fā)屬于自己的定制化啟動(dòng)器
譯文【51CTO譯文】我們要開發(fā)的就是這樣一套方案。
介紹
從最基本的概念角度來(lái)講,啟動(dòng)器其實(shí)應(yīng)該是一款能夠?qū)崿F(xiàn)以下功能的應(yīng)用程序:
- 它代表著一臺(tái)設(shè)備的主屏幕。
- 它能夠列出并啟動(dòng)已經(jīng)安裝在該設(shè)備當(dāng)中的應(yīng)用程序。
換句話來(lái)說(shuō),它就是那款用戶按下home按鈕后所顯示的應(yīng)用程序。除非大家已經(jīng)安裝了定制化啟動(dòng)器,否則我們目前正在使用的應(yīng)該都是Android系統(tǒng)自帶的默認(rèn)啟動(dòng)方案。不少設(shè)備制造商都會(huì)在產(chǎn)品中默認(rèn)使用由其定制的啟動(dòng)器,從而確保我們獲得與廠商預(yù)期相符的外觀效果與使用感受,例如三星TouchWiz以及HTC Sense。
在今天的教程中,我們將利用基本用戶界面創(chuàng)建出一款簡(jiǎn)單的啟動(dòng)器,它將由兩部分屏幕構(gòu)成:
- 在主屏幕中顯示的是該設(shè)備的墻紙圖案。
- 另一屏幕中顯示的是已經(jīng)安裝在設(shè)備當(dāng)中的應(yīng)用程序圖標(biāo)及其它細(xì)節(jié)信息。
1.要求
大家需要在自己的開發(fā)設(shè)備上預(yù)先安裝并配置好以下項(xiàng)目:
- Android SDK以及平臺(tái)工具
- Eclipse IDE 3.7.2或者更高版本,同時(shí)具備ADT插件
- 運(yùn)行有Android 2.2或者更高版本的模擬器或者Android設(shè)備
大家可以點(diǎn)擊此處通過(guò)Android開發(fā)者門戶下載對(duì)應(yīng)SDK及平臺(tái)工具。
2.項(xiàng)目設(shè)置
首先我們需要啟動(dòng)Eclipse并創(chuàng)建一個(gè)新的Android應(yīng)用程序項(xiàng)目。我為這個(gè)應(yīng)用取了個(gè)非常直白的名稱——SimpleLauncher,當(dāng)然大家也可以自由選擇自己想要的名稱。請(qǐng)確保軟件包名稱沒有與其它項(xiàng)目出現(xiàn)重復(fù)。我們的啟動(dòng)器所能支持的***SDK版本為“凍酸奶”,而主要的面向版本則為“果凍豆”。
由于我們不打算創(chuàng)建Activity,因此取消“Create Activity”勾選項(xiàng),然后點(diǎn)擊“Finish”以繼續(xù)。
3.項(xiàng)目清單
接下來(lái)我們需要通過(guò)添加兩個(gè)activity對(duì)AndroidManifest.xml文件進(jìn)行修改。***個(gè)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>
通過(guò)將android.intent.category.HOME與android.intent.category.DEFAULT兩個(gè)類添加至intent-filter組當(dāng)中,相關(guān)Activity得以擁有與啟動(dòng)器概念相符的運(yùn)行方式。當(dāng)大家按下設(shè)備上的home按鈕時(shí),其還將作為選項(xiàng)方案顯示出來(lái)。
我們還需要將launchMode設(shè)置到singleTask當(dāng)中,從而確保無(wú)論何時(shí)都只有單一Activity實(shí)例由系統(tǒng)負(fù)責(zé)運(yùn)行。要顯示用戶的墻紙圖案,大家必須將主題設(shè)置為Theme.Wallpaper.NoTitleBar.FullScreen。
我們需要添加的第二個(gè)Activity負(fù)責(zé)顯示已經(jīng)安裝在用戶設(shè)備中的應(yīng)用程序條目。它還有另一項(xiàng)任務(wù),即啟動(dòng)這些應(yīng)用程序。我們不需要對(duì)該Activity進(jìn)行任何特殊配置,將其命名為AppsListActivity即可。
- <activity
- android:name="ah.hathi.simplelauncher.AppsListActivity"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- >
- </activity>
4.Activity布局
下面在項(xiàng)目的res/layout文件夾中為HomeActivity類創(chuàng)建一個(gè)XML文件,并將其命名為activity_home.xml。該布局擁有一個(gè)單獨(dú)的Button用以響應(yīng)點(diǎn)觸事件。點(diǎn)觸該按鈕能夠讓用戶由主屏幕切換至應(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>
接下來(lái),在項(xiàng)目的res/layout文件夾中為AppsListActivity類創(chuàng)建一個(gè)XML文件并將其命名為activity_apps_list.xml。該布局當(dāng)中包含一個(gè)占據(jù)整個(gè)屏幕的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)建第三個(gè)XML文件并將其命名為list_item.xml。該文件用于定義ListView當(dāng)中各個(gè)條目的布局方案。列表視圖中的每個(gè)條目都代表著已經(jīng)安裝在用戶設(shè)備上的一款應(yīng)用程序。它能夠顯示該應(yīng)用程序的圖標(biāo)、標(biāo)簽以及軟件包名稱。我們可以利用ImageView實(shí)例來(lái)顯示該應(yīng)用的圖標(biāo),并通過(guò)TextView實(shí)例顯示標(biāo)簽與軟件包名稱。
- <?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)建兩個(gè)Activity類。當(dāng)創(chuàng)建這兩個(gè)類時(shí),請(qǐng)確保每個(gè)類的名稱都與我們之前在項(xiàng)目清單文件中所指定的內(nèi)容相匹配。
創(chuàng)建一個(gè)名為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)建完成的布局當(dāng)中。大家可能還記得,我們?cè)鵀閍ctivity_home布局添加過(guò)一個(gè)按鈕,用于觸發(fā)名為showApps的方法?,F(xiàn)在我們要做的是將該方法引入HomeActivity類當(dāng)中。整個(gè)添加過(guò)程非常簡(jiǎn)單,各位需要做的只是為AppsListActivity類創(chuàng)建一個(gè)Intent并付諸運(yùn)行。
#p#
AppsListActivity
創(chuàng)建另一個(gè)名為AppsListActivity的Activity類,而后將android.app.Activity設(shè)置為其超類。在該類的onCreate方法當(dāng)中,我們調(diào)用setContentView并將其傳遞至此前已經(jīng)創(chuàng)建完成的activity_apps_list布局當(dāng)中。
- 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);
- }
- }
雖然我們的啟動(dòng)器方案還沒有最終完成,但到這里大家已經(jīng)可以保存現(xiàn)有內(nèi)容并借此啟動(dòng)自己設(shè)備上的應(yīng)用程序了。當(dāng)各位按下設(shè)備上的home按鈕時(shí),系統(tǒng)會(huì)能夠彈窗詢問(wèn)我們希望使用哪種啟動(dòng)器方案。
如果大家選擇了Simple Launcher Home,則可以看到自己創(chuàng)建的全新主屏幕,其右上屏幕位置還配備一個(gè)按鈕。大家還能看到自己設(shè)備上原本設(shè)定的墻紙圖案。
現(xiàn)在回到Eclipse并創(chuàng)建一個(gè)名為AppDetail的類,其中將包含與應(yīng)用程序相關(guān)的細(xì)節(jié)信息、軟件包名稱、標(biāo)簽以及應(yīng)用程序圖標(biāo)。該界面非常基礎(chǔ),大家可以利用如下代碼實(shí)現(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方法當(dāng)中,我們可以使用PackageManager類的queryIntentActivities方法以獲取Intent.CATEGORY_LAUNCHER類別當(dāng)中的所有Intents。該查詢能夠返回一份列表,其中包含全部能夠經(jīng)由啟動(dòng)器實(shí)現(xiàn)啟動(dòng)的應(yīng)用程序。我們可以將查詢返回結(jié)果中的每個(gè)條目添加到名為apps的列表當(dāng)中。大家可以通過(guò)以下代碼片段進(jìn)一步了解其效果。
- 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變量當(dāng)中包含有我們所需要的全部細(xì)節(jié)信息,因此大家可以利用ListView類顯示出完整的應(yīng)用程序列表。我們首先創(chuàng)建一個(gè)簡(jiǎn)單的ArrayAdapter并覆蓋其getView方法以獲取列表中的條目信息。接下來(lái),將該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.偵聽點(diǎn)觸操作
當(dāng)用戶點(diǎn)觸ListView當(dāng)中的某個(gè)條目時(shí),我們的啟動(dòng)器應(yīng)該能夠運(yùn)行相應(yīng)的應(yīng)用程序。我們可以通過(guò)PackageManager類中的getLaunchIntentForPackage方法來(lái)創(chuàng)建一個(gè)Intent,用于指定我們要啟動(dòng)哪款應(yīng)用程序。請(qǐ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.通過(guò)整合實(shí)現(xiàn)完整功能
為了讓前面提到的全部?jī)?nèi)容整合起來(lái)并實(shí)現(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ùn)行我們的啟動(dòng)器應(yīng)用,并再一次運(yùn)行以查看結(jié)果。大家現(xiàn)在應(yīng)該已經(jīng)能夠在啟動(dòng)器主屏幕中點(diǎn)擊該按鈕后查看所有可以啟用的應(yīng)用程序了。別猶豫,快點(diǎn)觸其中一個(gè)嘗試一下吧。
總結(jié)
大家現(xiàn)在已經(jīng)擁有自己的定制化啟動(dòng)器了。它很簡(jiǎn)單也很粗糙,但我們完全可以陸續(xù)為其添加更多功能特性、從而讓它逐步得到完善。如果大家想進(jìn)一步了解能夠在啟動(dòng)器中引入哪些自定義項(xiàng)目,我建議各位點(diǎn)擊此處查看Android開發(fā)者門戶當(dāng)中給出的示例應(yīng)用程序。
原文鏈接:Build A Custom Launcher on Android
核子可樂(lè)譯