android Service學習

菜鳥筆記,高手繞過。android

文章內容列表:git

1.分別經過startService和bindService的方式啓動服務,比較二者不一樣,及在此期間發現的問題。github

2.研究IntentService的 使用。app


public class MyActivity extends Activity {
    
private String TAG="TAG";less

    Button startButton,stopButton,startIntentServiceButton,stopIntentServiceButton,jumpButton;
    ServiceConnection mServiceConnection;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        startButton= (Button) findViewById(R.id.button);
        stopButton= (Button) findViewById(R.id.button2);
        startIntentServiceButton= (Button) findViewById(R.id.intentService_button);
        stopIntentServiceButton= (Button) findViewById(R.id.stop_intentService);
        jumpButton= (Button) findViewById(R.id.jump_button);
        jumpButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              //  Intent intent=new Intent(MyActivity.this,SecondActivity.class);
               // startActivity(intent);
                MyActivity.this.finish();
                //android.os.Process.killProcess(android.os.Process.myPid());
            }
        });
        startIntentServiceButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.v(TAG,"startIntentServiceButton is pressed");
                MyIntentService myIntentService=new MyIntentService("myIntentService");
                Intent intent=new Intent(MyActivity.this,MyIntentService.class);
                startService(intent);
              // bindService(intent,mServiceConnection,Context.BIND_AUTO_CREATE);
            }
        });
        stopIntentServiceButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                Intent intent=new Intent(MyActivity.this,MyIntentService.class);
                stopService(intent);
                /**
                 * 當調用stopService方法時,service的onDestroy方法會當即被調用,可是服務裏面新開的線程還在跑,直到跑完。
                 */
               // unbindService(mServiceConnection);
            }
        });
        startButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.v(TAG, "BUTTON IS CLICKED");
               // startService(intent);
                /**
                 * IntentService的啓動方式跟service的啓動方式是同樣的,但他本身管理本身的service,此處調用了startService方式後,會調用onHandleIntent方法
                 * onHandleIntent-->onDestroy.
                 * 也就是說IntentService本身處理完onHandleIntent方法後,就會本身結束本身。大無畏的精神啊,而後就調用onDestroy了。
                 */
                Intent intent = new Intent(MyActivity.this, MyService.class);


                IntentService intentService;
                Handler handler;
                bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
               // startService(intent);
                /***
                 * 調用startService以後,service調用onCreate 和onStartCommand方法,經過該方法啓動的service會一直在運行,即便他的調用方已經結束了。
                 *因此若是使用這種方式啓動,If you implement this, it is your responsibility to stop the service
              
                /***
                 * 調用bindService要傳進去一個ServiceConnection 參數,bindService方法調用後會調用onCreate ,onBind方法,和onServiceConnected方法
                 * 調用次序是onCreate--->onBind----->onServiceConnected
                 * 經過該Binder能夠實現Service和調用方的通訊。
                 */
                /***
                 * 不論是startService仍是bindService方式啓動的服務。從啓動服務的activity跳轉到另外一個activity,
                 * 該服務也還會繼續跑。
                 * 可是二者的不一樣是:
                 * 當啓動服務的activity destroy掉不會影響startService方式啓動的service即便沒有調用stopService,也不會有影響
                 * 但經過bindService啓動的服務若是此時沒有主動調用unBindService,而後就調用啓動他的activity的finish方法,此時,該activity的
                 * onDestroy方法不會被調用,多是由於資源沒有釋放的緣由吧。若是此時你將你的程序按多任務鍵將其從歷史任務中劃掉,此時會調用onDestroy方法
                 * 固然也會報內存泄露的錯誤,由於以前沒有調onDestroy方法就是由於資源沒有釋放,固然是猜想了。
                 * 但還有一種狀況,若是你經過android.os.Process.killProcess(android.os.Process.myPid());
                 * 將程序殺死的話就不會報內存泄露的錯誤,也許該方法自己會幫你作些處理吧,可是activity的onDestroy方法依然不會被調用。
                 * 也就是說bindService方式啓動的service是依附於啓動他的activity的。
                 */
                Context context;


            }
        });
        stopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(MyActivity.this,MyService.class);
                unbindService(mServiceConnection);
               // stopService(intent);
            }
        });
        mServiceConnection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                MyService.MyBinder myBinder= (MyService.MyBinder) service;
                int count=myBinder.getCount();
                Log.v(TAG,"COUNT IS "+count);
            }


            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.v(TAG,"!!1--onServiceDisconnected");
            }
        };
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.my, menu);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.v(TAG,"---onDestroy");
    }
}

ide

MyService類:函數

public class MyService extends Service {
    private static String TAG="TAG";
    MyBinder myBinder=new MyBinder();
    int count=0;
    public MyService() {
    }


    /***
     *
     * @param intent
     * @return
     */
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.v(TAG,"ONBIND");
        return myBinder;


    }
    class MyBinder extends Binder{


        public int getCount(){


            return count;
        }
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v(TAG,"SERVICE ONSTARTCOMMAND");
        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v(TAG,"service onDestroy");
    }


    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(TAG,"SERVICE ONCREATE");
    }
}
oop

MyIntentService類:測試

public class MyIntentService extends IntentService {
    private static String TAG="TAG";
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public MyIntentService(String name) {
        super("MyIntentService");
    }
    public MyIntentService(){
        super("MyIntentService");
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        Log.v(TAG,"onHandleIntent");
        /*long futrueTime=System.currentTimeMillis()+5000;
        //執行5s鍾。
        while (System.currentTimeMillis()<futrueTime) {
            Log.v(TAG, "ONHANDLEINTENT");
            synchronized (this) {
                try {
                    Log.v(TAG,"WAIT");
                    wait(1000);


                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }*/
        for (int i=0;i<15;i++){
            Log.v(TAG,"ONHandleThread "+i);
            try {
                Log.v(TAG,"CurrentThread id is "+Thread.currentThread().getName());
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.v(TAG,"----onStartCommand");
        return super.onStartCommand(intent, flags, startId);


    }


    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(TAG,"----onCreate");
    }


    @Override
    public void onStart(Intent intent, int startId) {


        super.onStart(intent, startId);
        Log.v(TAG,"----INTENTSERVICE ONSTART");
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.v(TAG,"===onDestroy");
    }
ui

}

例子中有5個按鈕,startButton和stopButton測試startService和bindService,startIntentService和stopIntentService測試IntentService.jumpButton來結束啓動服務的activity.具體說明例子中有註釋。

1.1經過startService方法啓動的服務跟啓動方沒有關係,即便啓動方destroy了,服務依然跑。

1.2但經過bindService啓動的服務,必須在activity 調用destroy以前釋放資源,unBindService,否則會形成資源泄露。

1.3像上面例子中bindService以後,若是按中止按鈕去unBindService,直接按jumpButton去結束當前activity,你會發現當前activity的onDestroy方法並無被調到。此處注意下。

1.4此時從後臺任務裏將應用劃掉會報內存泄露的錯誤。若是用android.os.Process.killProcess(android.os.Process.myPid());去結束掉整個應用,你會發現不會報內存泄露的錯誤,即便沒有調用unBindService方法。

2.IntentService是Service的子類,也須要在manifest裏面進行註冊,其中要注意MyIntentService必需要有一個空的構造函數,如代碼中實現,不然註冊會編譯不過。

3.普通Service類是運行在主線程裏的,要進行耗時操做須要本身新開線程,但IntentService能夠進行耗時操做,直接在onHandleIntent方法裏進行耗時操做就好。耗時操做完成後自動調用onDestroy方法,這一點注意,若是在進行耗時操做時你顯式調用stopService的方式結束IntentService,這時IntentService的onDestroy方法會當即被調用,但耗時操做仍是會繼續執行,直到執行結束。這一點的原理能夠從IntentService的源碼中看出:

 

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;


    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }


        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }


    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }


    /**
     * Sets intent redelivery preferences.  Usually called from the constructor
     * with your preferred semantics.
     *
     * <p>If enabled is true,
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
     * {@link #onHandleIntent(Intent)} returns, the process will be restarted
     * and the intent redelivered.  If multiple Intents have been sent, only
     * the most recent one is guaranteed to be redelivered.
     *
     * <p>If enabled is false (the default),
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
     * dies along with it.
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }


    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.


        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();


        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }


    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }


    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }


    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }


    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null. 
     * @see android.app.Service#onBind
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     */
    protected abstract void onHandleIntent(Intent intent);

}

從源碼中能夠看出,IntentService內部新開啓了一個IntentThread的線程來處理耗時操做。當咱們經過startService的方式啓動IntentService時,會調用其的onStart和onStartCommand方法,這兩個方法裏面會去將你啓動IntentService時所用的Intent傳給Message的obj參數,而後將其發送給其內部的handler,在handler的handleMessage方法裏面就去調用handleIntent方法了,這就是爲何咱們啓動服務後IntentService就會去調用onHandleIntent方法的緣由了。同時咱們發如今handleMessage方法裏面onHandleIntent方法結束完以後,intentService就會調用stopSelf方法結束本身。IntentService的源碼仍是很是簡單的,相信你們都能看懂,記錄僅爲後來複習所用。如有錯誤,歡迎拍磚。代碼下載地址:https://github.com/happycodinggirl/AndroidLearningProcess.git

相關文章
相關標籤/搜索