Download presentation
Presentation is loading. Please wait.
Published byEverett Heath Modified 6年之前
1
Chapter 7 Android應用元件 Android應用元件可以幫助我們獲得系統資源訊息(ActivityManager)、提供系統服務(Service)、搜尋系統服務(SearchManager)、監聽Intent訊息(Broadcast Receiver)以及資料共享(ContentProvider和ContentResolver)。
2
ActivityManager
3
ActivityManager ActivityManager可管理所有的活動(activities),下表為ActivityManager所提供的巢狀類別。 類別名稱 功能介紹 ActivityManager.MemoryInfo 關於記憶體相關訊息 ActivityManager.ProcessErrorStateInfo 錯誤的程序訊息 ActivityManager.RecentTaskInfo 最近使用的任務訊息 ActivityManager.RunningAppProcessInfo 正在執行的程序訊息 ActivityManager.RunningServiceInfo 正在執行的服務訊息 ActivityManager.RunningTaskInfo 正在執行的任務訊息
4
ActivityManager 在本節中,介紹抓取剩餘記憶體為範例,程式碼如下:
public class ActivityManagerExample extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); TextView tv = (TextView) findViewById(R.id.info); ActivityManager myManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); // 建立ActivityManager.MemoryInfo物件 ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo(); // 利用getMemoryInfo方法獲取剩餘記憶體資訊 myManager.getMemoryInfo(outInfo); // 將得到之記憶體大小除1024轉換單位為KB tv.setText("剩餘記憶體: " + (outInfo.availMem/1024) + " KB"); } 在範例中,建構一個ActivityManager物件,並使用getSystemService方法來取得ACTIVITY_SERVICE的資訊,使用方法如下: ActivityManager myManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); 接著建構一個MemoryInfo物件,利用ActivityManager中的getMemoryInfo方法將資訊存入outInfo物件中,最後將availMem顯示在TextView上,由於availMem單位為Byte,故在此將其值置換為KiloByte,範例結果如圖7.1,左圖為程式所抓取的資料,右圖為系統內建工具抓取的資料。
5
ActivityManager 範例結果如下,左圖為範例執行結果,右圖為系統狀態顯示:
左圖為程式所抓取的資料,右圖為系統內建工具抓取的資料。
6
Service
7
Service Service是運行在背景的服務,如聽音樂時,可利用Service讓音樂在背景執行,這樣就可以關閉執行音樂的Activity來做其他事情,當要關閉音樂時,可以在抓取Service資訊後將其停止或是其他動作。 Service服務必須對應到AndroidManifest.xml。Service可由Activity來啟動,啟動之後可利用BroadcastReceiver 來取得相關Service訊息。
8
Service 本節範例利用Service服務在背景執行來實作一個簡易Timer,並利用Logcat來觀看結果,範例程式碼如下:
public class ServiceExample extends Activity { @Override public void onCreate(Bundle savedInstanceState) { // 略 myButton.setOnClickListener(new OnClickListener(){ public void onClick(View v) { if ( myButton.getText().equals("開始計時") ) { myButton.setText("停止計時"); Intent i = new Intent(ServiceExample.this, myService.class); startService(i); } else { myButton.setText("開始計時"); stopService(i); }); 範例主要分為兩個部分,Activity部分為ServiceExample,Service部分為myService,而範例是在Activity中啟用myService這個Service,使用方法如下: Intent i = new Intent(ServiceExample.this, myService.class); startService(i); 完整程式碼請參考光碟中 ServiceExample.java
9
Service 建立Service Class 完整程式碼請參考光碟中 myService.java
public class myService extends Service { // 此Thread每次迴圈會sleep 1秒用來計算此Service執行的總時間 // 並傳送Message訊息 // Service尚未結束則傳送PRINT Message // 當接收到Thread傳送Message訊息時,若訊息內容為PRINT則印出 // 此Service目前執行的總時間,若收到STOP訊息時則停止Thread運作 // 覆寫onStart讓Service開始時執行指定的動作 @Override public void onStart (Intent intent, int startId) { } // 覆寫onDestroy讓Service結束時執行指定的動作 public void onDestroy(){ // Service結束時傳送STOP Message用來停止Thread 而在myService中,我們override三個基本的Service Method,分別為: public void onStart (Intent intent, int startId) { // do something } onStart為startService時執行的Method。 public IBinder onBind(Intent intent) { // do something } onBind為Service必備的Method。 public void onDestroy(){ // do something } onDestroy為stopService時執行的Method。 啟動Service最基本的Method為onBind,而在本範例中,我們覆寫onStart以及onDestroy來啟動利用Thread實作的Timer以及結束Timer。在Activity中設置了一個按鈕,當按下去後則startService,此時會執行onStart,在此Method中建立並啟動一個自訂的TimerThread,此Thread每一秒會利用Message傳遞訊息給Handler,並用Log印出現在是第幾秒。當使用者在一次按下按鈕代表計時停止,此時會stopService並使用onDestroy,在此Method中會送一個Message訊息至Handler告知現在要停止Timer,此時會設定TimerThread中的stop標籤讓Timer結束掉 完整程式碼請參考光碟中 myService.java
10
Service 使用Service還必須將Service設定在AndroidManifest.xml中,如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android=" package="ncu.bnlab.ServiceExample" android:versionCode="1" android:versionName="1.0"> <application <activity android:name=".ServiceExample" <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".myService" android:exported="true"> </service> </application> <uses-sdk android:minSdkVersion="6" /> </manifest> 在Service中,android:name為執行之Service的Class名稱。第二個為exported,若設為true代表其他的應用程式也可以與這個Service作互動,若需要更進階的限制可再利用permission作進一步設定。
11
Service 範例結果如下: 當要關閉Sevice時,可以再抓取Service資訊後將其停止或是做其他動作。此範例當使用者再一次按下按鈕代表計時停止,此時會stopService並使用onDestroy,在此Method中會送一個Message訊息至Handler告知現在要停止Timer,此時會設定TimerThread中的stop標籤讓Timer結束掉
12
SearchManager
13
SearchManager SearchManager類別提供系統搜尋的服務,在正常情況下不會直接使用此類別來做應用,可利用Intent的ACTION_SEARCH或 context.getSystemService (Context.SEARCH_SERVICE)來應用搜尋服務。在許多應用程式中都會提供一個搜尋的介面,比較平常的做法是將此搜尋介面放在Menu中。 搜尋可分為兩種,「Local Search」以及「Globle Search」,Local Search搜尋範圍為應用程式定義的範圍,Globle Search則是搜尋整個系統。
14
SearchManager 在本範例中,實作一個簡單的搜尋範例,利用Menu以及一個EditText來實作。當Menu中有個Search的按鈕,當按下時會跳出一個簡易的快速搜尋列,而EditText中的文字則會自動被輸入至快速搜尋列當中,範例程式碼如下: public class SearchExample extends Activity { EditText searchEdit; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 設定搜尋為Local Search setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); searchEdit = (EditText) findViewById(R.id.SearchEdit); } public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 0, 0, "Search"); return true; public boolean onOptionsItemSelected(MenuItem item) { Bundle dataBundle = new Bundle(); String queryData = searchEdit.getText().toString(); startSearch(queryData, false, dataBundle, false); return super.onOptionsItemSelected(item);
15
SearchManager 啟動搜尋則是使用startSearch此Method,使用方法如下: 參數如下表所示:
startSearch (String initialQuery, boolean selectInitialQuery, Bundle appSearchData, boolean globalSearch) 類別名稱 功能介紹 initialQuery 若此字串不為空白,則會將此字串自動加在搜尋列上。 selectInitialQuery 若為true,則initialQuery會變成預設搜尋條件,當再輸入其他字會將原字串覆蓋掉。 appSearchData 應用程式可加入application-specific額外的內容來增加搜尋的條件 globalSearch 若為false,則看程式是否有設定,若也沒有預設設定,則自動使用Global Search方式;若為true,則設定為platform-global search
16
SearchManager 範例結果如下:
17
Broadcast Receivers
18
Broadcast Receivers BroadcastReceiver在許多手機應用程式上是必須的一個工具,當應用程式註冊一個BroadcastReceiver服務後,可利用onReceive方法來接收關於註冊之服務訊息,註冊方法如下: registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
19
Broadcast Receivers onReceive會根據程式跟系統註冊的IntentFilter來獲取相關服務訊息,在此簡單介紹一些關於電池與電源相關的filter如下表: 類別名稱 功能介紹 ACTION_BATTERY_CHANGED 電池狀態是否改變 ACTION_BATTERY_LOW 電池是否為低電量狀態 ACTION_BATTERY_OKAY 當電池狀態從低電量變為正常電量時會觸發此狀態 ACTION_POWER_CONNECTED 當裝置接上外部電源時 ACTION_POWER_DISCONNECTED 當裝置外部電源移除時
20
分頁選單 本節範例利用Toast顯示電量,當電量有改變時,BroadcastReceiver會計算改變後的電量,範例程式碼如下:
private BroadcastReceiver batteryReceiver = new BroadcastReceiver() { int level; int scale; @Override public void onReceive(Context context, Intent intent) String action = intent.getAction(); // 判斷接收到的事件是否為ACTION_BATTERY_CHANGED if (action.equals(Intent.ACTION_BATTERY_CHANGED)) // 設定電池level level = intent.getIntExtra("level", 0); // 設定電池scale scale = intent.getIntExtra("scale", 100); // 設定Toast停留長短 int duration = Toast.LENGTH_LONG; // 計算剩餘電量百分比 String text = "剩餘電量為:" + ( level * 100 / scale ) + "%"; Toast.makeText(context, text, duration).show(); } }; 在範例中,我們註冊一個BroadcastReceiver,如下: registerReceiver(batteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 當電池狀態發生變化時,即可收到BroadcastReceiver的資訊,當onReceive收到電池變化訊息時,我們利用Intent的getIntExtra方法抓取電池的兩個資料,一為level,另一個為scale。level會抓取當下電量的值,此值從0到EXTRA_SCALE,而scale則是代表電池最大的level。在計算剩餘電量時,將現在level / scale在乘100即為剩餘百分比。
21
Content Providers
22
Content Providers ContentProvider可提供一個介面給所有應用程式來分享資料,而分享資料的基本格式是利用URI來當成傳遞的媒介: 而ContentProvider的scheme為「content://」,而在CONTENT_URI中的各種URI都有ID,所以在向ContentProvider指定取得某個ID的資料,如下: 在此可利用ContentUris中的withAppendedId方法來幫URI加入ID: 或是利用Uri的withAppendedPath方法加入ID <scheme> : //<authority path-abempty> "?"<query> #<fragment> content : //. . . /35 Uri myUri = ContentUris.withAppendedId( Uri contentUri, long id ); withAppendedPath(Uri baseUri, String pathSegment);
23
Content Resolver
24
Content Resolver 在前面章節提到的ContentProvider可將Content分享至不同的應用程式之中,而ContentResolver則是一個標準的方式來取得ContentProvider所提供的資料,也是用來修改資料的方法,但若牽涉到寫入或修改資料的話,則要看目標的ContentProvider是否允許使用者對資料做存取的動作,若無此權限,則ContentResolver方法會失敗。 ContentProvider通常會使用URI的方式來當作分享資料的識別,故在ContentResolver要抓取某一ContentProvider資料時則必須將要抓取的URI當成參數來使用。
25
Content Resolver 在本節範例中,我們利用系統內建Phones.CONTENT_URI來得到電話中的聯絡人資訊並將其列表,範例程式碼如下: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ContentResolver cr = getContentResolver(); // Query聯絡人資料,並將結果儲存在Cursor中 Cursor c = cr.query(Contacts.Phones.CONTENT_URI, null, null, null, null); phoneInfo_Name = new String[c.getCount()]; phoneInfo_Number = new String[c.getCount()]; // 先看抓取之 cusor 是否有資料 if (c.moveToFirst()) { int nameColumn = c.getColumnIndex(Phones.NAME); int phoneColumn = c.getColumnIndex(Phones.NUMBER); int index = 0; do { phoneInfo_Name[index] = c.getString(nameColumn); phoneInfo_Number[index] = c.getString(phoneColumn); index++; } while (c.moveToNext()); } setListAdapter(new MyListAdapter(this)); 程式一開始建立一個ContentResolver物件,使用方法如下: ContentResolver cr = getContentResolver(); 接著使用ContentResolver中的query方法將所要抓取之URI傳入: // public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) Cursor c = cr.query(Contacts.Phones.CONTENT_URI, null, null, null, null);
26
Content Resolver ContentResolver的query參數如下表: 參數 功能描述 uri
projection 指定要回傳哪些欄位,若值為null代表全部回傳 selection 指定要回傳哪些列,若值為null代表全部回傳 selectionArgs 可在回傳條件中加入「?」,此陣列會依序取代未知的值 sortOrder 設定回傳結果的排序方式
27
Content Resolver 範例結果如下:
28
Content Resolver 本範例必須要在AndroidManifest.xml中加入下述權限方可正常運作:
<uses-permission android:name="android.permission.READ_CONTACTS"> </uses-permission>
29
Content Resolver 上面範例是取得ContentProvider的資料,而接著介紹如何透過ContentResolver來新增資料,要達到此動作則需使用ContentValues,此範例新增一筆聯絡人資料至通訊錄中,程式碼如下: ContentResolver cr = getContentResolver(); // 建立ContentValues物件 ContentValues values = new ContentValues(); // 設定People.NAME以及People.STARRED values.put(People.NAME, "NCU-FAX"); values.put(People.STARRED, 0); // 將上述設定的ContentValues物件Insert至People.CONTENT_URI中 Uri uri = cr.insert(People.CONTENT_URI, values); Uri phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY); values.clear(); // 設定People.Phones.TYPE(電話類型) values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE); // 設定People.Phones.NUMBER(電話號碼) values.put(People.Phones.NUMBER, " "); cr.insert(phoneUri, values); 要加入新資料首先先宣告一個ContentValues物件,使用其put方法將我們所要的資訊放到values物件中,接下來使用ContentResolver的insert方法將要加入之values加入目標URI中
30
Content Resolver 範例結果如下,左圖為未加入前,右圖為加入後:
31
Content Resolver ContentResolver與資料處理相關方法如下表: 類別名稱 功能介紹
delete(Uri url, String where, String[] selectionArgs) 刪除指定資料 insert(Uri url, ContentValues values) 加入指定資料 query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 查詢指定資料 update(Uri uri, ContentValues values, String where, String[] selectionArgs) 更新指定資料
32
Q&A
Similar presentations