安卓学习 之 Service服务(十)
服務(Service)是 Android 中實現(xiàn)程序后臺運行的解決方案,它非常適合用于去執(zhí)行那些不需要和用戶交互而且還要求長期運行的任務。
一、多線程編程
先介紹一下四個組件:
Message 是在線程之間傳遞的消息,它可以在內部攜帶少量的信息,用于在不同線程之間交換數(shù)據(jù)。上一小節(jié)中我們使用到了 Message 的 what 字段,除此之外還可以使用 arg1 和 arg2 字段來攜帶一些整型數(shù)據(jù),使用 obj 字段攜帶一個 Object 對象。
Handler 顧名思義也就是處理者的意思,它主要是用于發(fā)送和處理消息的。發(fā)送消息一般是使用 Handler 的 sendMessage()方法,而發(fā)出的消息經(jīng)過一系列地輾轉處理后, 最終會傳遞到 Handler 的 handleMessage()方法中。
MessageQueue是消息隊列的意思,它主要用于存放所有通過 Handler 發(fā)送的消息。這部分消息會一直存在于消息隊列中,等待被處理。每個線程中只會有一個 MessageQueue 對象。
Looper 是每個線程中的 MessageQueue 的管家,調用 Looper 的 loop()方法后,就會進入到一個無限循環(huán)當中,然后每當發(fā)現(xiàn) MessageQueue 中存在一條消息,就會將它取出,并傳遞到 Handler 的 handleMessage()方法中。每個線程中也只會有一個 Looper 對象。
public class MainActivity extends Activity implements OnClickListener { public static final int UPDATE_TEXT = 1;private TextView text; private Button changeText;private Handler handler = new Handler() {public void handleMessage(Message msg) { switch (msg.what) {case UPDATE_TEXT:// 在這里可以進行UI操作text.setText("Nice to meet you"); break;default:break;}}};@Overridepublic void onClick(View v) { switch (v.getId()) {case R.id.change_text:new Thread(new Runnable() { @Overridepublic void run() {Message message = new Message(); message.what = UPDATE_TEXT;handler.sendMessage(message); // 將Message對象發(fā)送出去}}).start(); break;default:break;} }使用 AsyncTask
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {@Overrideprotected void onPreExecute() {progressDialog.show(); // 顯示進度對話框}@Overrideprotected Boolean doInBackground(Void... params) {try {while (true) {int downloadPercent = doDownload(); // 這是一個虛構的方法publishProgress(downloadPercent);if (downloadPercent >= 100) {break;}}} catch (Exception e) {return false;}return true;}@Overrideprotected void onProgressUpdate(Integer... values) {// 在這里更新下載進度progressDialog.setMessage("Downloaded " + values[0] + "%");}@Overrideprotected void onPostExecute(Boolean result) {progressDialog.dismiss(); // 關閉進度對話框// 在這里提示下載結果if (result) {Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show();} else {Toast.makeText(context, " Download failed", Toast.LENGTH_SHORT).show();}} }在 doInBackground()方法里去執(zhí)行具體的下載任務。這個方法里的代碼都是在子線程中運行的,因而不會影響到主線程的運行。注意這里虛構了一個doDownload()方法,這個方法用于計算當前的下載進度并返回。
調用 publishProgress()方法并將當前的下載進度傳進來,這樣 onProgressUpdate()方法就會很快被調用,在這里就可以進行 UI 操作了。
當下載完成后,doInBackground()方法會返回一個布爾型變量,這樣 onPostExecute()方法就會很快被調用,這個方法也是在主線程中運行的。然后在這里我們會根據(jù)下載的結果來彈出相應的 Toast 提示,從而完成整個 DownloadTask 任務。
簡單來說,使用 AsyncTask 的訣竅就是,在 doInBackground()方法中去執(zhí)行具體的耗時任務,在 onProgressUpdate()方法中進行 UI 操作,在 onPostExecute()方法中執(zhí)行一些任務的收尾工作。
二、服務的基本用法
其中 onCreate()方法會在服務創(chuàng)建的時候調用,onStartCommand()方法會在每次服務啟動的時候調用,onDestroy()方法會在服務銷毀的時候調用。onBind()方法目前暫時將它忽略掉。
二、活動與服務之間的通信
啟動服務之后,活動與服務無關。只是活動通知服務一下:你可以啟動了,具體做什么不知道,完成的如何也不知道。 那么如何讓活動與服務更緊密一些:那就要用上面的onbind方法了。
目的:在 MyService 里提供一個下載功能,然后在活動中可以決定何時開始下載,以及隨時查看下載進度。
可以看到onServiceConnected傳進一個Ibinder實例。
三、服務的生命周期
有onCreate、onStartCommand、onBind和onDestroy等方法都是在服務生命周期內可能調用的方法。
任何位置調用startService方法,服務會啟動起來,并回調onStartCommand方法;若服務未曾創(chuàng)建,則onCreate會先于onStartCommand方法;服務啟動后會運行,直到onStopService或StopSelf方法被調用;
還可以調用bindService來獲得服務持久連接,此時回調bind方法,若未創(chuàng)建過,則會先onCreate再onbind,onBind方法會返回IBinder對象實例。自由通信了已經(jīng)可以。
bindService綁定后用unbindService解綁,此時會調用onDestroy方法;startService啟動后會調用stopService來結束服務。若同時調用了startService,bindService兩個方法,則必須同時調用stopService和unbindservice才可會執(zhí)行onDestroy方法,因為android機制規(guī)定了服務被啟動和綁定之后,會一直處于運行狀態(tài)。
四、服務的更多技巧
前臺服務與普通服務最大區(qū)別在于:他有一個正在運行的圖標在系統(tǒng)狀態(tài)欄顯示,下拉通知欄可看到更加詳細,類似通知。比 如:彩云天氣,后臺更新天氣數(shù)據(jù),在系統(tǒng)欄一直顯示當前天氣信息。
與Notifiction比較類似,構建的notification并沒有使用NotificationManager顯示出來,而是調用startForeGround來使MyService變成一個前臺服務,并在系統(tǒng)狀態(tài)欄顯示處出來。
@Override public void onCreate() {super.onCreate();Log.d(TAG, "onCreate executed ");Intent intent = new Intent(this, MainActivity.class);PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);Notification notification = new NotificationCompat.Builder(this).setContentTitle("This is contnet title").setContentText("This is contnet Text").setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)).setContentIntent(pi).build();startForeground(1,notification); }服務默認在主線程中進行,若在服務中處理耗時邏輯,則很容易出現(xiàn)ANR。這是采用多線程編程技術,在服務的每個方法中開啟一個子線程去處理耗時邏輯。服務執(zhí)行完后自動停止,可以使用StopSelf方法。
@Override public int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "onStartCommand executed ");new Thread(new Runnable() {@Overridepublic void run() {//處理具體邏輯//服務執(zhí)行完后自動停止,可以使用StopSelf方法stopSelf();}});return super.onStartCommand(intent, flags, startId); }IntentService主要用于解決程序員忘記開啟線程,或者忘記調用stopSelf()方法
public class MyIntentService extends IntentService {protected void onHandleIntent(Intent intent) {//處理具體邏輯} }總結
以上是生活随笔為你收集整理的安卓学习 之 Service服务(十)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓学习 之 多媒体技术(八)
- 下一篇: 安卓学习 之 网络技术(十)