android service探究(附:使用服務功能下載文件)

像service一樣做後臺默默的勞動者,還是如acticity光鮮亮麗走在臺前

在android設計中,作爲四大組件之一service有着不可替代的功能,可是實際開發項目中使用的並不多,或者說它的作用有些時候被activity,第三方開源支持給弱化了。不管怎麼說,基礎的使用時我們進化的階梯,本節來說說service的那些事。

  1. service的啓動類型:

啓動型

    services : context.startService() --> onCreate() --> onStart() -->      service running --> context.stopService() --> onDestroy() --> Service stop;

方法的調用順序:

Intent intent = new Intent(this,ServicesClass.class);
//啓動服務
StartServices(intent);
|
//進入服務類
|
//當服務沒有創建的時候,onCreate()方法進行調用
|
onStartCommand(Intent intent, int flags, int startId)
|
stopService()
|
onDestroy()

綁定型

     services:  context.bindService() --> onCreate() --> onBind() --> service running --> onUnbind() --> onDestroy() --> service stop

方法調用的順序

private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {//獲取service }
        @Override
        public void onServiceDisconnected(ComponentName name) {}
    };

Intent intent = new Intent(this,ServicesClass.class);
//啓動並且綁定服務,這裏需要一個ServiceConnection參數,所以需要在調用的類中聲明
|
bindService(Intent service, ServiceConnection conn,int flags)
|
//如果服務沒有被實例化過onCreate()方法進行調用
//此時服務中的該方法啓動
public IBinder onBind(Intent intent){return bind}
|
//因爲返回的對象爲IBinder 所以在service中定義一個類進行繼承Binder
|
//可以在個類中定義自己所需要的方法來進行相應的邏輯功能
public class MyBinder extends Binder {
        @Override
        public String getInterfaceDescriptor() {
            return super.getInterfaceDescriptor();
        }
}
|
//在主類中調用裏面的方法`conn` 中進行方法強轉類型,直接獲取Service實例,***表示自己定義的方法,這樣就可以與主類進行數據傳遞,邏輯溝通
|
返回類型聲明 = ((ServicesClass.MyBinder)(service)).***;
|
unbindService(ServiceConnection conn)
|
onUnbind(Intent intent)
|
onDestroy() 

2.服務的進階技巧
使用前臺服務:服務幾乎都是在後臺進行的,一直以來在後臺默默工作提供服務,但是服務的系統優先級是比較低,在系統內存緊張時便會回收正在後臺運行的服務,當你的app在運行時及時系統內存緊張也不能回收你的服務時便可以使用前臺服務

/*啓動前臺服務的方法兩個參數 */
public final void startForeground(int id, Notification notification) {
        try {
            mActivityManager.setServiceForeground(
                 new ComponentName(this, mClassName), mToken, id,
                    notification, true);
        } catch (RemoteException ex) {
        }
    }

在receiver的onCreate()方法中添加如下代碼

Intent intent = new Intent(this,MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,0);

Notification notification = new NotificationCompat.Builder(this).setContentTitle("讓我偷偷看你").setStyle(new NotificationCompat.BigTextStyle().bigText("頭輕輕一擡,望見你的風采,扶流蘇的裙襬,臉上掛着粉黛,微微的笑像小孩,站在你家門外,輕輕的把門敲開,害羞的地下腦袋,讓我偷偷看你,在你回眸的春風裏"))
.setSmallIcon(R.mipmap.ic_launcher)                  .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.setContentIntent(pendingIntent).setWhen(System.currentTimeMillis()).build();
//啓動前臺的服務
startForeground(1,notification);

//停止前臺服務

stopForeground(true);// 停止前臺服務--參數:表示是否移除之前的通

3.關於IntentService

子實踐中,服務是在主線程開啓的,所以如果服務中有耗時的操作,那麼就需要對service開啓線程

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    //需要進行開啓線程的操作
    new Thread(new Runnable(){
        @Override
        public void run(){
            //處理相應的邏輯內容
                ···//服務中的方法處理完成後,如果牽扯到UI處理,還需要進行處理
            stopSelf();
        }
    }).start();
}

所以,android系統提供另外一種方法IntentService

1.首先是自己定義類繼承IntentService
2.創建構造函數,在其內部調用父類的有參構造函數
3.在類中實現onHandleIntent()方法

說白了,跟使用Service類似,因爲IntentService繼承的父類是Service

4 . 說說AsyncTask的這些事
在android多線程編程中,提供asyncTask方法進行線程的管理。相比起Thread和Handler的使用,asyncTask的使用相對來講更加簡單,我們並不需要知道它內部的實現邏輯,只需要書寫我們自己的邏輯方法即可。
先看代碼:

public class DownLoadTask extends AsyncTask<String ,Integer,Integer> {
    public DownLoadTask() {}
    /**
     * 在進行doInBackground方法之前進行調用,執行準備工作
     * 屬於主線程範疇
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    /**
     * 在doInBackground完成之後進行調用
     * 屬於主線程範疇
     * @param integer
     */
    @Override
    protected void onPostExecute(Integer integer) {
        super.onPostExecute(integer);
    }
    /**
     * 更新方法進行進度的提示
     * 屬於主線程範疇,這裏可以進行UI更新操作
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }

    /**
     *這個方法用來書寫邏輯耗時操作,屬於另開子線程的範疇
     * 使用:Thread.currentThread().getId()查看子線程Id
     * @param params
     * @return
     */
    @Override
    protected Integer doInBackground(String... params) {
    return 0;
    }

在使用asyncTask時候,需要實現上述方法來進行邏輯操作,對於AsyncTask<Params, Progress, Result>的參數說明一下:
@params Params:表示傳入的參數,在進行異步請求時所需值,並在doInBackground()中進行使用
@params Progress:進度值,在onProgressUpdate()進行使用,主動調用該方法的時候需要在doInBackground()方法中調用publishProgress()方法
@params Result:結果判斷值,也就是說當doInBackground()執行完畢之後會主動調用onPostExecute()方法,但是對於耗時的操作中,可能的情況:成功、失敗、中斷等等,這時的參數便可以作爲判斷參數進行邏輯處理。

關於方法的調用:

downLoadTask = new DownLoadTask();
downLoadTask.execute("自己定義的參數類型值");

另外補充說明:因爲asyncTask中execute()使用的是單一線程池,若你需要好幾個asyncTask同時執行,需要使用如下的調用

 /**
         * 參數說明:executeOnExecutor(Executor exec,Params... params)
         *
         * @params exec  引用 java.util.concurrent.Executors包的newCachedThreadPool()方法
         *
         *                另一種方法自己定義線程池:Executor exec = new ThreadPoolExecutor(15, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
         * 效果允許在同一時刻有15個任務正在執行,並且最多能夠存儲200個任務。
         *
         * @params params 同execute()中的方法
         */
downLoadTask.executeOnExecutor(java.util.concurrent.Executors.newCachedThreadPool(),downloadUrl);

方法來進行啓動。

最後:在這裏附加一段代碼,來查詢你的服務是否開啓

//代碼有點問題,先放着,後面找找在來改進
public static boolean isServiceExisted(Context context,String className){

        ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);

        List<ActivityManager.RunningServiceInfo> serviceInfoList = activityManager.getRunningServices(Integer.MAX_VALUE);

        if (!(serviceInfoList.size()>0)){

            return false;
        }
        for (int i = 0; i<serviceInfoList.size();i++){

            ActivityManager.RunningServiceInfo serviceInfo = serviceInfoList.get(i);

            ComponentName componentName = serviceInfo.service;

            System.out.println("componentName.getClassName()--------------->"+componentName.getClassName());

            if (componentName.getClassName().equals(className)){

                return true;
            }else{

                return false;
            }

        }
        return false;
    }

關於使用服務下載文件的源碼地址,請在個人github平臺進行下載
https://github.com/wedfrendwang/Service.git

猜猜這句歌詞是哪首民謠 —-春風又吹紅了花蕊,你也已經添了新歲。

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