Android四大組件——Service

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 讓定時任務的觸發時間從系統時間開始算起,但不會喚醒CPU
  • AlarmManager.ELAPSED_REALTIME_WAKUP 讓定時任務的觸發時間從1970年1月1日0時開始算起,會喚醒CPU
  • RTC 讓定時任務的觸發時間從系統時間開始算起,但不會喚醒CPU
  • `RTC_WAKEUP 讓定時任務的觸發時間從1970年1月1日0時開始算起,但不會喚醒CPU

2.定時任務觸發的時間,以毫秒爲單位。
3.這裏我們一般調用getBroadcast()方法來獲取一個能夠執行廣播的PendingIntent,這樣當定時任務被觸發時,廣播接收器的onReceive()方法可以得到執行。

創建實例演示

  1. 創建新項目 新建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);
    }
}
  1. 新建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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章