Service基礎篇

Service(服務)是一個沒有用戶界面的在後臺運行執行耗時操作的應用組件。其他應用組件能夠啓動Service,並且當用戶切換到另外的應用場景,Service將持續在後臺運行。另外,一個組件能夠綁定到一個service與之交互(IPC機制)。首先明確一點,儘管Service是進行後臺計算的,但它仍然是運行在主線程中,處理耗時造作仍然需要在子線程處理。

Service的分類,根據調用者和service在不在同一個進程裏,Service可以分爲:本地服務(LocalService)、遠程服務(RemoteService)。

它的作用:1.耗時操作的執行:ANR對Activity和BroadcastReceiver響應時間的限制(Activity對事件響應不超過5秒,BroadcastReceiver執行不超過10秒),使得在其中都不適合執行較耗時操作,這樣像網絡、數據庫、複雜計算這類耗時操作的執行就需要一個組件來承擔。Service作爲Android四大組件之一,其功能之一就是耗時操作的執行另外相對於Thread的耗時操作。

2.Service的可控性。任何 Activity 都可以控制同一 Service,而系統也只會創建一個對應 Service 的實例。Service可以在任何有 Context 的地方調用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,來控制它,你也可以在 Service 裏註冊 BroadcastReceiver,在其他地方通過發送 broadcast 來控制它,而新產生的Thread在銷燬了它的Activity仍然可以運行,但已經沒有辦法對這可Thread操控。。

3.應用內或應用間數據通信(IPC通信):Android每個應用程序都在自己的dalvik虛擬機中運行,一個應用是不允許訪問其他應用的內存信息的,爲此Android引入了Content Provider在不同應用間共享數據,BroadcastReceiver廣播信息給不同應用程序,但Content Provider更多用於數據的共享,BroadcastReceiver廣播的信息會被所有應用接收較耗費系統資源,對於兩個應用間動態的進行交互還需要通過Service來完成。

本地服務(LocalService)

調用者和service在同一個進程裏,所以運行在主進程的main線程中。所以不能進行耗時操作,可以採用在service裏面創建一個Thread來執行任務,service影響的是進程的生命週期。Service有兩種啓動狀態,Service這兩種狀態可以共存。

第一種是直接start方式開啓service,主要用於執行後臺的計算。

使用service的步驟:

1,定義一個類繼承service

2,manifest.xml文件中配置service

3,使用context的startService(Intent)方法啓動service

4,不在使用時,調用stopService(Intent)方法停止服務

使用start方式啓動的生命週期:onCreate() -- > onStartCommand() -- > onDestory()

注意:如果服務已經開啓,不會重複回調onCreate()方法,如果再次調用context.startService()方法,service而是會調用onStart()或者onStartCommand()方法。停止服務需要調用context.stopService()方法,服務停止的時候回調onDestory被銷燬。

特點:一旦服務開啓就跟調用者(開啓者)沒有任何關係了。開啓者退出了,開啓者掛了,服務還在後臺長期的運行,開啓者不能調用服務裏面的方法。

第二種是綁定狀態bind的方式啓動,主要用於和其他組件交互。

使用service的步驟:

1,定義一個類繼承Service

2,在manifest.xml文件中註冊service

3,使用context的bindService(Intent,ServiceConnection,int)方法啓動service

4,不再使用時,調用unbindService(ServiceConnection)方法停止該服務

使用這種start方式啓動的service的生命週期如下:onCreate() -- > onBind() --> onUnbind() -- > onDestory()  (注意:綁定服務不會調用onStart()或者onStartCommand()方法)

特點:bind的方式開啓服務,綁定服務,調用者掛了,服務也會跟着掛掉。綁定者可以調用服務裏面的方法。

DEMO:ServiceLifeCycle類中的兩個靜態方法是爲了在驗證啓動模式的,主動關閉當前服務的效果,也可以通過廣播的形式來關閉開啓的服務。

public class ServiceLifeCycle extends Service {

    private static ApkActivity m;
    private String TAG = "ServiceLifeCycle";

    public static void startService(Context context) {
        if (null != context) {
            m = (ApkActivity) context;
            Intent intent = new Intent(context, ServiceLifeCycle.class);
            // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startService(intent);
        }
    }

    public static void stopService(Context context) {
        if (null != context) {
            Intent intent = new Intent(context, ServiceLifeCycle.class);
            // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.stopService(intent);
        }
    }

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

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

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.e(TAG, "onStart(...)");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy()");
        if (m != null) {
            m.finish();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind(...)");
        return new MyBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG, "onUnbind(...)");
        return super.onUnbind(intent);
    }


    public class MyBinder implements IBinder {

        @Override
        public String getInterfaceDescriptor() throws RemoteException {
            return null;
        }

        @Override
        public boolean pingBinder() {
            return false;
        }

        @Override
        public boolean isBinderAlive() {
            return false;
        }

        @Override
        public IInterface queryLocalInterface(String descriptor) {
            return null;
        }

        @Override
        public void dump(FileDescriptor fd, String[] args) throws RemoteException {

        }

        @Override
        public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {

        }

        @Override
        public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return false;
        }

        @Override
        public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException {

        }

        @Override
        public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
            return false;
        }
    }


}
public class TestActivity extends Activity {

 
    MyServiceConnection myServiceConnection;

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

    private void initView() {
        myServiceConnection = new MyServiceConnection();
        TextView mStart = (TextView) findViewById(R.id.start_service);
        TextView mStop = (TextView) findViewById(R.id.stop_service);
        mStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // ServiceLifeCycle.startService(ApkActivity.this);
                bindService(new Intent(TestActivity.this, ServiceLifeCycle.class), myServiceConnection, BIND_AUTO_CREATE);
            }
        });
        mStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //靜態方法關閉
                // ServiceLifeCycle.stopService(ApkActivity.this);
                unbindService(myServiceConnection);
            }
        });
    }

    private void testStartService() {
        Intent mService = new Intent(this, ServiceLifeCycle.class);
        startService(mService);
    }


    private class MyServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            ServiceLifeCycle.MyBinder myBinder = (ServiceLifeCycle.MyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}

xml佈局簡單就不在提供了。

註冊列表:

<service android:name=“.downloadApk.ServiceLifeCycle"/>

startService啓動打印結果:

 05-17 04:03:17.216 19745-19745/com.algorithm.algorithm E/ServiceLifeCycle: onCreate()

05-17 04:03:17.216 19745-19745/com.algorithm.algorithm E/ServiceLifeCycle: onStartCommand()

05-17 04:03:17.216 19745-19745/com.algorithm.algorithm E/ServiceLifeCycle: onStart(...)

bindService打印:

05-17 08:25:02.112 1348-1348/com.algorithm.algorithm E/ServiceLifeCycle: onCreate()

05-17 08:25:02.112 1348-1348/com.algorithm.algorithm E/ServiceLifeCycle: onBind(…)

點擊unbindService,打印:

05-17 08:26:15.408 1348-1348/com.algorithm.algorithm E/ServiceLifeCycle: onUnbind(...)

05-17 08:26:15.408 1348-1348/com.algorithm.algorithm E/ServiceLifeCycle: onDestroy()

2.遠程服務

調用者和service不在同一個進程中,service在單獨的進程中的main線程,是一種垮進程通信方式.

綁定遠程服務的步驟:

a.在服務的內部創建一個內部類,提供一個方法,可以間接調用服務的方法

b.把暴露的接口文件的擴展名改爲.aidl文件 去掉訪問修飾符

c.實現服務的onbind方法,繼承Bander和實現aidl定義的接口,提供給外界可調用的方法

d.在activity 中綁定服務。bindService()

e.在服務成功綁定的時候會回調 onServiceConnected方法 傳遞一個 IBinder對象

f. AIDL定義的接口.Stub.asInterface(binder) 調用接口裏面的方法

具體的內容可以參照我之後的文章:android AIDL

========================================

文章借鑑了:http://www.jianshu.com/p/51aaa65d5d25

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