編輯:關於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後一定能重啟。
Android基礎入門教程——10.4 Vibrator(振動器)
本節引言: 本節我們介紹的是Vibrator(振動器),是手機自帶的振動器,別去百度直接搜針振動器,因為 你的搜索結果可能是如圖所示的神秘的道具,或者其他神秘
Android Tab -- 使用Fragment、FragmentManager來實現
效果: 代碼:https://github.com/ldb-github/Layout_Tab1、布局:使用LinearLayout布置標簽;再使用FrameL
android內存優化之三內存分析工具的使用
一.Eclipse Heap分析內存洩露Android開發中避免不了碰到內存洩露問題,這裡先大概講下內存洩露的基本概念:內存洩露官方的解釋是是用動態存儲分配函數動態開辟的
Android進程保活招式大全
目前市面上的應用,貌似除了微信和手Q都會比較擔心被用戶或者系統(廠商)殺死問題。本文對 Android 進程拉活進行一個總結。Android 進程拉活包括兩個層面:A.