1. 程式人生 > >Android -Services 使用簡介

Android -Services 使用簡介

blog ani start cti gen tlist line exception lis

Android Services 四大組件之一,主要用於後臺長時間運行。沒有界面。這裏講解兩種services的啟動還有AIDL通信方式。

1.startservices

a.建立繼承services的類,復寫方法(本地服務)

public class MyServices extends Service  {

    private static final String TAG="TestTag";

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
return null; } @Override public void onCreate() { Log.i(TAG, "onCreate"); super.onCreate(); } @Override public void onStart(Intent intent, int startId) { Log.i(TAG, "onStart"); super.onStart(intent, startId); } @Override
public void onDestroy() { Log.i(TAG, "onDestroy"); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand"); return super.onStartCommand(intent, flags, startId); } }

b.聲明AndroidManifest

<service android:name=".MyServices"/>

c.啟動關閉

switch(v.getId()){
                case R.id.btnStart:
                    startService(intent);
                    break;
                case R.id.btnStop:
                    stopService(intent);
                    break;
  }

後記:

服務生命周期:context.startService() ->onCreate()- >onStart()- >onStartCommand()->Service running ->context.stopService() ->onDestroy() ->Service stop

如果Service還沒有運行,則android先調用onCreate()然後調用onStartCommand(),每次調用startService(Intent)的時候,都會調用執行onStartCommand();
如果Service已經運行,則只調用onStartCommand()。

2.bindservices

服務鏈接(ServiceConnection)或直接獲取Service中狀態和數據信息
服務鏈接能夠獲取Service的對象,因此綁定Service的組件可以調用Service中的實現的函數
使用Service的組件通過Context.bindService()建立服務鏈接,通過Context.unbindService()停止服務鏈接
如果在綁定過程中Service沒有啟動,Context.bindService()會自動啟動Service
同一個Service可以綁定多個服務鏈接,這樣可以同時為多個不同的組件提供服務

a.創建BindService繼承Service

public class BindService extends Service {

    private static final String TAG="BindService";

    private BindServiceX myBinderServiceX=new BindServiceX();
    public class BindServiceX extends Binder{
        public BindService getBindService() {
            return BindService.this;
        }
    }

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        Log.i(TAG, "onBind");
        return myBinderServiceX;
    }

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





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

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

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

    public void ShowLog(){
        Log.i(TAG, "BindService=>ShowLog");
    }

}

b.聲明AndroidManifest

<service android:name=".BindService"/>

c.啟動使用

public void onClick(View v) {
            Intent intentBind = new Intent(MainActivity.this, BindService.class);

            switch (v.getId()) {
                case R.id.btnStartBindService:
                    bindService(intentBind, conn, Context.BIND_AUTO_CREATE);
                    break;
                case R.id.btnStopBindService:
                    if (isConn) {
                        unbindService(conn); //不可以多次調用
                        isConn=false;
                    }
                    break;
            }

後記:

AndroidServiceActivity綁定方法,Context.BIND_AUTO_CREATE表明只要綁定存在,就自動建立Service;同時也告知Android系統,這個Service的重要程度與調用者相同,除非考慮終止調用者,否則不要關閉這個Service。

如果service沒被創建,那麽調用一次onCreate(),然後調用onBind(),多次綁定時,不會多次調用onBind()。

通過unbindService()函數取消綁定Servcie時,onUnbind()函數將被調用,
如果onUnbind()函數的返回true,則表示在調用者綁定新服務時,
onRebind()函數將被調用

取消綁定僅需要使用unbindService()方法,並將ServiceConnnection傳遞給unbindService()方法需註意的是,unbindService()方法成功後,系統並不會調用onServiceDisconnected(),因為onServiceDisconnected()僅在意外斷開綁定時才被調用

3.AIDL IPC通信 services

Android系統中,各個應用都運行在自己的進程中,進程之間一般無法直接進行通信,為了實現進程通信(interprocess communication,簡稱IPC),android提供了AIDL Service;

Android需要AIDL(Android Interface Definition Language)來定義遠程接口,這種接口定義語言並不是一種真正的變成語言,只是定義兩個進程之間的通信接口

與Java接口相似,但是存在如下幾點差異

  • AIDL定義接口的源代碼必須以.aidl結尾

  • AIDL用到的數據類型,除了基本類型、String、List、Map、CharSequence之外,其它類型全部都需要導包,即使它們在同一個包中也需要導包;

AIDL的步驟:

a.創建AIDL文件

package com.example.zcx.servicesdemo;

// Declare any non-default types here with import statements

//interface ICat {
//    /**
//     * Demonstrates some basic types that you can use as parameters
//     * and return values in AIDL.
//     */
//    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
//            double aDouble, String aString);
//}
interface ICat {
    String getColor();
    double getWeight();
}

b.服務端編寫

public class AidlService extends Service {
    String[] colors = new String[] { "紅色", "黃色", "黑色" };
    double[] weights = new double[] { 2.3, 3.1, 1.58 };
    private String color;
    private double weight;
    private CatBinder catBinder;
    Timer timer = new Timer();

    @Override
    public void onCreate() {
        super.onCreate();
        catBinder = new CatBinder();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                // 隨機地改變service組件內的color,weight屬性的值
                int rand = (int) (Math.random() * 3);
                color = colors[rand];
                weight = weights[rand];
                System.out.println("---------" + rand);
            }
        }, 0, 800);
    }


    @Override
    public IBinder onBind(Intent arg0) {
        /**
         * 返回CatBinder對象,在綁定本地Service情況下,
         * 該catBinder會直接傳給客戶端的ServiceConnected對象的ServiceConnected
         * ()方法的第二個參數;在綁定遠程Service的情況下
         * ,只將catBinder對象的代理傳給客戶端的ServiceConnected對象的ServiceConnected()方法的第二個參數
         */
        return catBinder;
    }

    @Override
    public void onDestroy() {
        timer.cancel();
    }

    /**
     * 繼承Stub,也就是實現了ICat接口,並實現了IBinder接口
     *
     * @author pengcx
     *
     */
    public class CatBinder extends ICat.Stub {
        @Override
        public String getColor() throws RemoteException {
            return color;
        }

        @Override
        public double getWeight() throws RemoteException {
            return weight;
        }
    }
}

androidmanifest:

<service android:name=".AidlService" android:process=":remote">
            <intent-filter>
                <action android:name="org.crazyit.aidl.AIDL_SERVICE" />
            </intent-filter>
</service>

c.客戶端使用

首先需要建立aidl,註意要在相同的包名下,否則報錯: java.lang.SecurityException: Binder invocation to an incorrect interface

// ICat.aidl
package com.example.zcx.servicesdemo;

// Declare any non-default types here with import statements

//interface ICat {
//    /**
//     * Demonstrates some basic types that you can use as parameters
//     * and return values in AIDL.
//     */
//    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
//            double aDouble, String aString);
//}
interface ICat {
    String getColor();
    double getWeight();
}

編寫客戶端:

public class MainActivity extends AppCompatActivity {

    private ICat catService;
    private Button getButton;
    private EditText colorEditText, weightEditText;

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            catService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 獲取遠程Service的onBinder方法返回的對象代理
            catService = ICat.Stub.asInterface(service);
            Log.d("zcx","catService");
        }
    };
    public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }
        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);
        // Set the component to be explicit
        explicitIntent.setComponent(component);
        return explicitIntent;
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getButton = (Button) findViewById(R.id.getbutton);
        colorEditText = (EditText) findViewById(R.id.coloredittext);
        weightEditText = (EditText) findViewById(R.id.weightedittext);

        // 創建所需要綁定的Service的Intent
        Intent intent = new Intent();
        intent.setAction("org.crazyit.aidl.AIDL_SERVICE");
        //intent.setPackage(getPackageName());
        Intent eintent = new Intent(getExplicitIntent(this,intent));
        Log.e("zcx","eintent = "+eintent);
        // 綁定遠程的服務
        Log.e("zcx"," "+bindService(eintent, conn, Service.BIND_AUTO_CREATE));

        getButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 獲取並顯示遠程service的狀態
                try {
                    colorEditText.setText(catService.getColor());
                    weightEditText.setText(catService.getWeight() + "");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 解除綁定
        this.unbindService(conn);
    }
}

Android -Services 使用簡介