Service的基本用法
完整代碼請見:longlong’s github
定義一個服務
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
重寫服務中最常用的三個方法:onCreate()
服務創建的時候調用 onStartCommand()
每次服務啓動的時候調用 onDestroy()
服務銷燬的時候調用
在AndroidMainifest.xml文件中註冊服務:
<service android:name=".MyService"> </service>
啓動和停止服務
1.在xml中添加四個按鈕
2.新建MyService服務
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder {
//思路:創建一個專門的Binder對象來對下載功能進行管理。
public void StartDownload() {
System.out.print("startDownload executed");
}
public int grtProgress() {
System.out.print("getProgress executed");
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate(){
super.onCreate();
System.out.println("onCreate executed");
}
@Override
public int onStartCommand(Intent intent,int flags,int startId){
System.out.println("onStartCommand executed");
return super.onStartCommand(intent,flags,startId);
}
@Override
public void onDestroy(){
super.onDestroy();
System.out.println("onDestroy executed");
}
}
3.MainActivity中
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button startService;
private Button stopService;
private Button bindService;
private Button unbindService;
private MyService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
//創建一個ServiceConnection的匿名類,重寫以下兩種方法:在活動與服務綁定和解除時使用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//向下轉型得到DownloadBinder實例,進行簡單的下載 顯示進度 測試
downloadBinder = (MyService.DownloadBinder)service;
downloadBinder.StartDownload();
downloadBinder.grtProgress();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService = (Button)findViewById(R.id.bind_service);
unbindService = (Button)findViewById(R.id.unbind_service);
startService = (Button)findViewById(R.id.start_service);
stopService = (Button)findViewById(R.id.stop_service);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.start_service:
Intent startIntent = new Intent(this,MyService.class);
startService(startIntent);//啓動活動
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this,MyService.class);
stopService(stopIntent);//停止活動
break;
case R.id.bind_service:
Intent bindIntent = new Intent(this,MyService.class);
bindService(bindIntent,connection,BIND_AUTO_CREATE);
break;
//將MainActivity和MyService進行綁定。三個參數:Intent對象;ServiceConnection實例;標誌位 BIND_AUTO_CREATE表示在活動和服務綁定後自動創建服務——使得onCreate()方法執行。
case R.id.unbind_service:
unbindService(connection);//解除服務。
break;
default:
break;
}
}
}
挨個點擊效果圖:
注意
每調用一次stopService()
方法,onStartCommand()
方法就會執行一次,但實際上每個服務都只存在一個實例,所以銷燬時只需調用一次stopService()
方法或者
stopSelf()
方法。
一個既調用了startService()方法和bindServicae()方法的服務,要想銷燬掉,必須同時調用stopService()方法和unbindService()方法,onDestroy()方法纔會執行。
IntentService的使用
服務默認運行在主線程中,若在服務裏添加一些耗時的邏輯,可能會出現ANR(application not responding)的情況,此時,一個比較標註的服務:在MyService中的onStartCommand()
方法中添加以下代碼 缺點:一旦啓動便會一直運行 需要stopService()
方法或者stopSelf()
方法
@Override
public int onStartCommand(Intent intent,int flags,int startId){
new Thread(new Runnable){
@Override
public void run(){
//處理耗時邏輯
}
}).start();
return super.onStartCommand(intent,flags,startId);
}
新建一個MyIntentService類繼承自IntentService(不要忘記註冊):
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
//打印當前線程的id
Log.d("MyIntentService", "Thread id is" + Thread.currentThread().getId());
//在這個方法中去實現一些具體的邏輯,因爲這個方法已經在子線程中運行了。
}
@Override
public void onDestroy(){
super.onDestroy();
Log.d("MyIntentService","onDestroy executed");
}
}
添加一個StartIntentService按鈕:
case R.id.start_intent_service:
//打印主線程的id
Log.d("MainActivity","Thread id is"+Thread.currentThread().getId());
Intent intentService = new Intent(this,MyIntentService.class);
startService(intentService);
break;
//在點擊事件中啓動MyIntentService服務。
點擊按鈕後:
Service實現 後臺執行定時服務
- 安卓定時任務有兩種:java API中提供的Timer類:android的Alarm機制。
- Alarm:具有喚醒CPU的功能(喚醒CPU和喚醒屏幕不是一個概念)
- Timer:不適用長期在後臺執行的定時任務。
Alarm機制的用法
//獲取一個AlarmManager實例
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//調用其set()方法就可以設定一個定時任務了,比如設定一個任務在10秒之後執行:
long triggerAtTime = SystemClock.elapsedRealtime()+10*1000;
manager.set(AlarmManager.ELAPSED_REALTIME_WAKUP,triggerTime,pendingIntent);
//SystemClock.elapsedRealtime()可以獲取系統開機至今所經歷的毫秒數
//System。currentTimeMillis()可以獲取1970年1月1日0時至今所經歷的毫秒數
//System。currentTimeMillis() + RTC_WAKEUP 也可以實現
set()方法的三個參數:
1.整型參數(用於指定Alarm的工作類型):
AlarmManager.ELAPSED
讓定時任務的觸發時間從系統時間開始算起,但不會喚醒CPUAlarmManager.ELAPSED_REALTIME_WAKUP
讓定時任務的觸發時間從1970年1月1日0時開始算起,會喚醒CPURTC
讓定時任務的觸發時間從系統時間開始算起,但不會喚醒CPU- `RTC_WAKEUP 讓定時任務的觸發時間從1970年1月1日0時開始算起,但不會喚醒CPU
2.定時任務觸發的時間,以毫秒爲單位。
3.這裏我們一般調用getBroadcast()
方法來獲取一個能夠執行廣播的PendingIntent,這樣當定時任務被觸發時,廣播接收器的onReceive()
方法可以得到執行。
創建實例演示
- 創建新項目 新建LongRunningService類並註冊
public class LongRunningService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId){
//在onStartCommand()方法裏開一個子線程,進行邏輯操作
new Thread(new Runnable() {
@Override
public void run() {
Log.d("LongRunningService","executed at"+new Date().toString());
}
}).start();
AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);
int anhour = 10*1000; //十秒的毫秒數
long triggerAtTime = SystemClock.elapsedRealtime()+anhour;
Intent i = new Intent(this,AlarmManager.class);
PendingIntent pi = PendingIntent.getBroadcast(this,0,i,0);
//用PendingIntent指定處理定時任務時的廣播接收器爲AlarmManager 當然要建一個AlarmReceiver類
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pi);
return super.onStartCommand(intent,flags,startId);
}
}
- 新建AlarmReceiver類並註冊
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context,LongRunningService.class);
context.startService(i);
}
}
一旦啓動LongRunningService,就會在onStartCommand()
方法中設定一個定時任務,這樣10s後AlarmReceiver的onReceive()
方法會得到執行,我們在這裏再次啓動LongRunningService,實現無限循環。接下來的思路:打開程序的時候啓動一次LongRunningService。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this,LongRunningService.class);
startService(intent);
}
}