第一行代碼筆記 service基本用法

服務簡介:

作爲四大組件之一的服務可以運行在後臺,但是服務並不是運行在一個獨立的進程當中,而是依賴於創建服務時所在的應用程序進程。當某個應用程序進程被殺死時,所有依賴於該進程的服務也會停止運行。另外服務並不會自動開啓線程,所有的代碼都是默認運行在主線程當中。也就是說,我們需要在服務的內部手動創建子線程,並在這裏執行具體的任務。否則就有可能出現主線程被阻塞住的情況。


插曲android多線程

一般通過匿名內部類

new Thread(new Runnable() {
    @Override
    public void run() {
      
    }
}).start();

定義一個單獨的類的時候,一般實現Runnable接口。而不繼承thread 繼承的方式耦合較高。

注意子線程裏不要做更新UI的操作,如果要更新,可以通過handle的異步消息處理。或者通過回調接口。或者AsyncTask。或者

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        showDatas.setText(msg);
    }
});

AsyncTask的簡單說明

/**
 * AsyncTask三個參數
 * 參數1:在執行AsyncTask時需要傳入的參數。可用於後臺任務中
 * 參數2.後臺任務執行時,如需顯示進度,則使用這裏指定的泛型作爲進度單位
 * 參數3.但任務執行完畢後,如果需要返回結果,則這裏指定的泛型作爲返回值類型
 */
public class AsyncTaskDemo extends AsyncTask<Void, Integer, Boolean> {

    /**
     * 在後臺任務執行之前調用,用於進行界面上的初始化操作,比如顯示一個進度對話框
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    /**
     * 在這裏處理所有的耗時任務,任務一旦完成通過return返回
     * 這裏不能對UI進行操作,因爲此處代碼都運行在子線程中。
     *
     * @param params
     * @return
     */
    @Override
    protected Boolean doInBackground(Void... params) {
//        如果要更新進度條,調用publishProgress來完成
//        publishProgress();
        return null;
    }

    /**
     * 這裏可以更新UI了
     *
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

    }

    /**
     * 但後臺任務完成後return後這個方法馬上會執行
     * 並且rentur的值可以在參數中獲得。這裏做收尾工作
     *
     * @param aBoolean
     */
    @Override
    protected void onPostExecute(Boolean aBoolean) {
        super.onPostExecute(aBoolean);
    }

    /**
     * 這裏執行這個異步任務
     */
    private void start() {
        new AsyncTaskDemo().execute();
    }
}

迴歸服務基本用法

一 最基礎示例:

第一步:通過new service創建一個service,好處是自動去清單文件中註冊了這service

 <service
        android:name=".day05.service.MyService"
        android:enabled="true"
        android:exported="true" />

    <activity android:name=".day05.service.MyServiceActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

/**
 * 注意服務使用也是要去清單文件註冊的。
 * 除了通過activity中 stopService(stopIntent);停止服務
 * 也可以在此類中調用 stopSelf();來停止服務
 *
 * 注意有時候我們既通過startService來開啓了服務,又調用了bindService
 * 這時候要服務停止,必須調用stopService和unBindService
 */
public class MyService extends Service {
    public MyService() {
    }

    /**
     * 在服務創建的時候調用一次
     */
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("MyService:onCreate", "onCreate");
    }

    /**
     * 在服務啓動的時候每次都會調用,希望服務一啓動就執行的動作,邏輯寫在這。
     * 但是注意每調用一次startService(intent)這個方法就會被執行一次。
     * 但是每個服務都只有一個實例,所以不管調用了多少次的startService只需要調用
     * 一次stopService活stopSelf方法,服務就會停下來
     * @param intent
     * @param flags
     * @param startId
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 在服務銷燬的時候調用,回收那些不在使用的資源
     */
    @Override
    public void onDestroy() {
        Log.i("MyService:onDestroy", "onDestroy");
        super.onDestroy();
    }

    /**
     * 通過bind來進行activity和服務之間的通信
     *
     * @param intent
     * @return
     */
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.i("MyService:onBind", "onBind");
//        throw new UnsupportedOperationException("Not yet implemented");
        return mBinder;
    }

    private DownloadBinder mBinder = new DownloadBinder();

    class DownloadBinder extends Binder {
        public void startBownload() {
            Log.i("DownloadBinder", "startBownload");
        }

        public int getProgress() {
            Log.i("DownloadBinder", "getProgress");
            return 0;
        }


    }
}

第二步:創建activity來開啓這個服務

public class MyServiceActivity extends AppCompatActivity implements View.OnClickListener {

//   通過binder的方式可以更好的控制service啓動去執行的任務
    private MyService.DownloadBinder downLoadBinder;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downLoadBinder = (MyService.DownloadBinder) service;
            downLoadBinder.startBownload();
            downLoadBinder.getProgress();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_service);

        initView();
    }

    private void initView() {
        findViewById(R.id.startService).setOnClickListener(this);
        findViewById(R.id.stopService).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.startService:
//                啓動方式一
//                Intent intent = new Intent(this,MyService.class);
//                startService(intent);

//                啓動方式二
                Intent intent = new Intent(this,MyService.class);
                bindService(intent,connection,BIND_AUTO_CREATE);

                break;
            case R.id.stopService:
//                停止方式一
//                Intent stopIntent = new Intent(this,MyService.class);
//                stopService(stopIntent);

//                停止方式二
                unbindService(connection);
                break;
        }
    }
}

二 使用前臺服務

服務幾乎都是後臺運行的。在後臺運行時,他的系統優先級比較低,當系統出現內存不足時,就坑呢個會被回收掉。如果不想由於系統內存不足被回收,就提高它的優先級,使用前臺服務。他和普通服務的最大區別在於,他會在系統的狀態欄下一直顯示一個正在運行的圖標。

示例:只要在創建的MyService的onCreate方法添加一個通知,如下

@Override
public void onCreate() {
    super.onCreate();
    Log.i("MyService:onCreate", "onCreate");
    Intent intent = new Intent(this, MyServiceActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    Notification build = new NotificationCompat.Builder(this)
            .setContentTitle("前臺服務")
            .setContentText("我的前臺服務創建")
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentIntent(pendingIntent)
            .build();
    startForeground(1,build);
}

三    IntentService的使用

因爲服務也是運行在主線程的,所以如果要做耗時操作時,要自己開一個子線程進行,否則容易出現程序沒有響應(ANR),另外有時候粗心,不記得unbindService 或者stopService 來停止服務,這時候就又一個IntentService,它能自己開線程執行相應的操作,並且執行完畢後,自動關閉服務。使用方式和之前一樣,創建一個類繼承IntentService 在清單文件註冊這個service 然後在activity中通過intent    startSerive()來開啓這個服務。

public class MyIntentService extends IntentService {
    public MyIntentService() {
//        調用父類的有參構造函數
        super("MyIntentService");
    }

    public MyIntentService(String name) {
        super(name);
    }

    /**
     * 在這裏執行要做的動作,並且已經是開了子線程,不用自己再開線程了,等待這裏執行完,
     * 會自動註銷這個service
     * @param intent
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        Log.i("MyIntentService", "onHandleIntent  sleep before");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.i("MyIntentService", "onHandleIntent  sleep after");
        Log.i("MyIntentService", "onHandleIntent");
        Log.i("MyIntentService", "onHandleIntent  id: "+Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        Log.i("MyIntentService", "onDestroy");
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章