編輯:關於Android編程
正文
1 Started Service介紹
Started Service,即被啟動的服務。它是2種常見服務之一,另一種是Bound Service。Started Service常被用在執行進程的某個後台操作,如通過該服務來實現文件下載等功能。
實現步驟和使用方法
(01) 創建一個Started Service類,該類要繼承於Service。
(02) 在Started Service類中實現以下接口:
onStartCommand():必須實現!在其中啟動服務提供的功能。例如,若該服務是在後台下載文件,則在該函數中啟動一個新的線程(Thread),在線程中實現下載功能。當客>戶端通過startService()啟動函數時,系統會自動執行服務對應的onStartCommand()函數。
onBind():必須實現!返回null即可。onBind()是Bound Service中用到的函數,在Started Service服務不會執行onBind();但必須實現它,因為onBind()是Service類
的抽象方法。
onCreate():可以不用實現,視用戶需求而定。當服務被創建時,系統會自動調用該函數。一般在該函數中進行初始化工作,例如:新建線程。
onDestroy():可以不用實現,視用戶需求而定。當服務被銷毀時,系統會自動調用該函數。一般在該函數中進行清除工作,例如,終止並回收線程。
(03) 客戶端通過startService()啟動服務。
(04) 客戶端通過endService()結束服務。
下面以實際例子來說明“Started Service”的實現方式。
2 Service示例
采用Service來實現“Android IntentService”中的示例,即:編寫一個activity,包含2個按鈕和1個進度條,2個按鈕分別是開始按鈕、結束按鈕。點擊“開始”按鈕:進度條開始加載;“開始”變成“重啟”按鈕;顯示“結束”按鈕(默認情況,“結束”按鈕是隱藏狀態)。
BaseServiceTest包括了兩個主要的類:
StartServiceImpl.java —— Service的子類。當服務被啟動時,它會並新建一個線程,每隔200ms將一個數字+2,並通過廣播發送出去。
StartServiceTest.java —— 調用StartServiceImpl的Activity。
StartServiceImpl.java的內容如下:
package com.skywang.service; import android.os.IBinder; import android.app.Service; import android.content.Intent; import android.util.Log; import java.lang.Thread; /** * @desc 服務:每隔200ms將一個數字+2並通過廣播發送出去 * @author skywang * */ public class StartServiceImpl extends Service { private static final String TAG = skywang-->StartServiceImpl; // 發送的廣播對應的action private static final String COUNT_ACTION = com.skywang.service.startservice.COUNT_ACTION; // 線程:用來實現每隔200ms發送廣播 private static CountThread mCountThread = null; // 數字的索引 private static int index = 0; @Override public void onCreate() { Log.d(TAG, onCreate); super.onCreate(); } @Override public void onDestroy() { Log.d(TAG, onDestroy); // 終止服務 if ( mCountThread != null) { mCountThread.interrupt(); mCountThread = null; } super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, onStartCommand); // 非首次運行服務時,執行下面操作 // 目的是將index設為0 if ( mCountThread != null) { Log.d(TAG, mCountThread != null); index = 0; return START_STICKY; } Log.d(TAG, start thread); // 首次運行時,創建並啟動線程 mCountThread = new CountThread(); mCountThread.start(); return START_STICKY; } @Override public IBinder onBind(Intent intent) { Log.d(TAG, onBind); return null; } private class CountThread extends Thread { @Override public void run() { index = 0; try { while (true) { // 將數字+2, index += 2; // 將index通過廣播發送出去 Intent intent = new Intent(COUNT_ACTION); intent.putExtra(count, index); sendBroadcast(intent); // Log.d(TAG, CountThread index:+index); // 若數字>=100 則退出 if (index >= 100) { if ( mCountThread != null) { mCountThread = null; } return ; } // 修改200ms this.sleep(100); } } catch (InterruptedException e) { e.printStackTrace(); } } } }StartServiceTest.java的內容如下:
package com.skywang.service; import android.os.Bundle; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.util.Log; public class StartServiceTest extends Activity { private static final String TAG = skywang-->StartServiceTest; private static final String COUNT_ACTION = com.skywang.service.startservice.COUNT_ACTION; private CurrentReceiver mReceiver; private Button mStart = null; private Button mStop = null; private Intent mIntent = null; private Intent mServiceIntent = null; private ProgressBar mProgressBar = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.start_service_test); mStart = (Button) findViewById(R.id.start); mStart.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { Log.d(TAG, click start button); // 顯示“結束”按鈕 mStop.setVisibility(View.VISIBLE); // 將“開始”按鈕更名為“重啟”按鈕 mStart.setText(R.string.text_restart); // 啟動服務,用來更新進度 if (mServiceIntent == null) mServiceIntent = new Intent(com.skywang.service.StartService); startService(mServiceIntent); } }); mStop = (Button) findViewById(R.id.stop); mStop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d(TAG, click stop button); if (mServiceIntent != null) { // 結束服務。 stopService(mServiceIntent); mServiceIntent = null; } } }); mStop.setVisibility(View.INVISIBLE); mProgressBar = (ProgressBar) findViewById(R.id.pbar_def); // 隱藏進度條 mProgressBar.setVisibility(View.INVISIBLE); // 動態注冊監聽COUNT_ACTION廣播 mReceiver = new CurrentReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(COUNT_ACTION); this.registerReceiver(mReceiver, filter); } @Override public void onDestroy(){ super.onDestroy(); if(mIntent != null) stopService(mIntent); if(mReceiver != null) this.unregisterReceiver(mReceiver); } /** * @desc 更新進度條 * @param index */ private void updateProgressBar(int index) { int max = mProgressBar.getMax(); if (index < max) { mProgressBar.setProgress(index); mProgressBar.setVisibility(View.VISIBLE); } else { // 隱藏進度條 mProgressBar.setVisibility(View.INVISIBLE); // 隱藏“結束”按鈕 mStop.setVisibility(View.INVISIBLE); // 將“重啟”按鈕更名為“開始”按鈕 mStart.setText(R.string.text_start); } // Log.d(TAG, progress : +mProgressBar.getProgress()+ , max : +max); } /** * @desc 廣播:監聽COUNT_ACTION,獲取索引值,並根據索引值來更新進度條 * @author skywang * */ private class CurrentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (COUNT_ACTION.equals(action)) { int index = intent.getIntExtra(count, 0); updateProgressBar(index); } } } }layout文件start_service_test.xml的內容如下:
manifest內容如下:
點擊下載: 源代碼
效果圖:
3 補充說明
在示例中,我們自定義了onStartCommand()的返回值。Android API文檔中說明它的返回值,可以有以下4種:
START_STICKY
如果service進程被kill掉,保留service的狀態為開始狀態,但不保留遞送的intent對象。隨後系統會嘗試重新創建service,由於服務狀態為開始狀態,所以創建服務後一定會調用onStartCommand(Intent,int,int)方法。如果在此期間沒有任何啟動命令被傳遞到service,那麼參數Intent將為null。
START_NOT_STICKY
“非粘性的”。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統不會自動重啟該服務。
START_REDELIVER_INTENT
重傳Intent。使用這個返回值時,如果在執行完onStartCommand後,服務被異常kill掉,系統會自動重啟該服務,並將Intent的值傳入。
START_STICKY_COMPATIBILITY
START_STICKY的兼容版本,但不保證服務被kill後一定能重啟。
本節引言: 本節我們介紹的是Vibrator(振動器),是手機自帶的振動器,別去百度直接搜針振動器,因為 你的搜索結果可能是如圖所示的神秘的道具,或者其他神秘
效果: 代碼:https://github.com/ldb-github/Layout_Tab1、布局:使用LinearLayout布置標簽;再使用FrameL
一.Eclipse Heap分析內存洩露Android開發中避免不了碰到內存洩露問題,這裡先大概講下內存洩露的基本概念:內存洩露官方的解釋是是用動態存儲分配函數動態開辟的
目前市面上的應用,貌似除了微信和手Q都會比較擔心被用戶或者系統(廠商)殺死問題。本文對 Android 進程拉活進行一個總結。Android 進程拉活包括兩個層面:A.