Android Service的使用

類型和區(qū)別

  • 特點(diǎn):沒有UI,后臺(tái)運(yùn)行
  • Started
    • 啟動(dòng)方式startSevice()
    • 一旦啟動(dòng),在后臺(tái)永遠(yuǎn)運(yùn)行,除非主動(dòng)停止或者被kill
    • 通常不返回值(可發(fā)一個(gè)PendingIntent, 用廣播返回值)
  • Bound
    • 啟動(dòng)方式bindService()
    • 只要有應(yīng)用綁定到它,就在運(yùn)行。當(dāng)沒有應(yīng)用綁定時(shí),service被摧毀。
    • 多個(gè)應(yīng)用可以綁定到一個(gè)bind service.
    • BroadcastReceiver不能綁定到服務(wù)
    • 可以返回值,以及做進(jìn)程間通信(IPC)
  • 一個(gè)service可以同時(shí)實(shí)現(xiàn)onStartCommand()和onBind()
  • 注意:Service是在主線程上運(yùn)行,不要進(jìn)行耗時(shí)操作


    image.png

創(chuàng)建一個(gè)新的service

  1. 重寫父類方法

    • onStartCommand(). 被startService()調(diào)用,需要用stopSelf() or stopService()手動(dòng)停用
    • onBind(),當(dāng)調(diào)用bindSerivce()的時(shí)候會(huì)調(diào)用,需要返回一個(gè)IBinder
    • onCreate(). 一次性,如service已經(jīng)在運(yùn)行,則不再調(diào)用
    • onDestroy(). 前臺(tái)服務(wù)>綁定到活動(dòng)的服務(wù)>后臺(tái)服務(wù)>長(zhǎng)時(shí)間運(yùn)行的后臺(tái)服務(wù). 服務(wù)會(huì)被kill,當(dāng)有資源時(shí),會(huì)嘗試恢復(fù)。對(duì)于started服務(wù),需要考慮當(dāng)系統(tǒng)自動(dòng)恢復(fù)時(shí)的處理。這根據(jù)onStartCommand()時(shí)的返回值有所不同:
      • START_STICKY, 重新啟動(dòng)時(shí),傳入的intent是null
      • START_STICKY_COMPATIBILITY, 不保證會(huì)重新調(diào)用onStartCommand()
      • START_NOT_STICKY, 不自動(dòng)重啟
      • START_REDELIVER_INTENT, 總是重新發(fā)送上次的intent
      • 可以通過flag來判斷服務(wù)的性質(zhì)START_FLAG_REDELIVERY, START_FLAG_RETRY
  2. 修改Manifest

    • android:enabled=["true" | "false"]
    • android:exported=[“true” | “false”],如果為false,只有相同userID的能訪問。如果有intent filter,默認(rèn)為true,如果沒有,默認(rèn)為false
    • android:icon="drawable resource“
    • android:isolatedProcess=[“true” | “false”], 為true時(shí),將運(yùn)行在獨(dú)立進(jìn)程中
    • android:label="string resource“
    • android:name="string“
    • android:permission=“string“,如果設(shè)置,只有擁有權(quán)限的才能訪問
    • android:process=“string”

IntentService & Stop Service &前臺(tái)服務(wù)

  • Intent Service
    • Service的子類,推薦的實(shí)現(xiàn)Started Service的方法。會(huì)自動(dòng)為每個(gè)request創(chuàng)建worker thread.
    • 自動(dòng)創(chuàng)建隊(duì)列進(jìn)行處理,不用擔(dān)心線程沖突
    • 隊(duì)列處理完畢自動(dòng)stopSelf()
    • 自動(dòng)為不可bind的(可以通過重寫來實(shí)現(xiàn)可bind)
    • 只需要兩點(diǎn):
      • 構(gòu)造函數(shù)中調(diào)用父類
      • 實(shí)現(xiàn)onHandleIntent()方法
    • 可以重寫其它方法,但要記得返回父類函數(shù)
  • 停止Service
    • 當(dāng)stop service時(shí),如果多個(gè)request同時(shí)在處理,stopSelf()可能會(huì)把新發(fā)起的request結(jié)束掉,所以推薦使用stopSelf(int),這樣會(huì)比較當(dāng)前正在處理的request是不是結(jié)束的目標(biāo)。
    • 記得stopSelf(),這是消耗系統(tǒng)資源的。
  • 前臺(tái)Service
    • 提供必需的notification和id, 用startForeground(ONGOING_NOTIFICATION_ID, notification) 啟動(dòng),用stopForeground(boolean removeNotification)停止
    • stopForeground并不停止服務(wù),而只是會(huì)讓前臺(tái)notification消失

Bounded Service

創(chuàng)建bounded service的三種方式

  • 擴(kuò)展Binder類,如果只是自己的應(yīng)用內(nèi)使用,用這種方式。
  • 使用Messenger,可實(shí)現(xiàn)IPC的最簡(jiǎn)單(?)的方法,線程安全,C/S端都用Handler來處理消息
  • 使用AIDL,優(yōu)點(diǎn)是可以同時(shí)處理多個(gè)請(qǐng)求,對(duì)于大部分的app,Google并不推薦使用這種方式(但是在framework里面有很多)
    onBind()只在第一次綁定時(shí)執(zhí)行一次,后續(xù)再綁定時(shí)返回第一次的Ibinder對(duì)象
    當(dāng)調(diào)用服務(wù)的方法時(shí),要捕獲DeadObjectException異常,這個(gè)異常標(biāo)明service不存在了
  • bindServices的flag
    • BIND_AUTO_CREATE
    • BIND_DEBUG_UNBIND,只用于調(diào)試。當(dāng)設(shè)置時(shí),以后的unbind請(qǐng)求的callstack會(huì)被保存
    • BIND_IMPORTANT,允許客戶端把服務(wù)升級(jí)為“前臺(tái)”優(yōu)先級(jí),一般只能升級(jí)到“可見”優(yōu)先級(jí)
    • BIND_NOT_FOREGROUND,不允許把被綁定的服務(wù)升級(jí)為“前臺(tái)”優(yōu)先級(jí)。
    • BIND_ABOVE_CLIENT,道友比貧道更重要
    • BIND_ADJUST_WITH_ACTIVITY,如從activity發(fā)起,那么允許優(yōu)先級(jí)隨其可見性來調(diào)整
    • BIND_ALLOW_OOM_MANAGEMENT, 讓擁有該服務(wù)的進(jìn)程來自己管理優(yōu)先級(jí)
    • BIND_WAIVE_PRIORITY,放棄調(diào)整優(yōu)先級(jí),讓系統(tǒng)像對(duì)待普通應(yīng)用一樣對(duì)待

擴(kuò)展Binder類方式

  • Service端
    • 實(shí)現(xiàn)一個(gè)Binder實(shí)例,其中包含可調(diào)用的方法或者其它包含可調(diào)用方法的類示例(包括當(dāng)前的service類)
    • 在onBind()時(shí)返回該實(shí)例
  • Client端
    • 綁定時(shí)傳入connection參數(shù)(一個(gè)ServiceConnection的實(shí)例),綁定是異步的,并不返回Binder
    • 在connection的onServiceConnected()方法中接收實(shí)例,并轉(zhuǎn)換類型為Binder類型,然后調(diào)用需要的方法
    • 實(shí)現(xiàn)connection的onServiceDisconnected()方法,處理服務(wù)crash和被kill時(shí)的情況
  • 示例代碼
//服務(wù)端:
public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();//實(shí)例化
    // Random number generator
    private final Random mGenerator = new Random();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {//實(shí)現(xiàn)Binder,其中有可返回當(dāng)前service的方法
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    /** method for clients */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

//客戶端:
public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

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

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);//開啟Activity時(shí)綁定service,綁定后立即返回,connection作為參數(shù)傳入
                                                                   //綁定完成后,將會(huì)調(diào)用connection的onServiceConnected方法,客戶端將在
                                                                   //那里接收Binder,并轉(zhuǎn)型,然后得到要可調(diào)用方法的類,或者該Binder就包含可調(diào)方法
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    /** Called when a button is clicked (the button in the layout file attaches to
      * this method with the android:onClick attribute) */
    public void onButtonClick(View v) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call were something that might hang, then this request should
            // occur in a separate thread to avoid slowing down the activity performance.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** Defines callbacks for service binding, passed to bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

使用Messenger方式

  • Service端
    • 創(chuàng)建Handler來處理消息
    • 用Handler創(chuàng)建一個(gè)Messenger
    • 在onBind()中返回Messenger創(chuàng)建的IBinder
  • Client端
    • 用得到的IBinder去創(chuàng)建Messenger
    • 用Messenger發(fā)消息指揮Service的Handler運(yùn)行
    • (如需要回復(fù)),創(chuàng)建Client端的Messenger,在send()命令的replyTo參數(shù)中傳入這個(gè)Messenger
  • Sample:
//服務(wù)端:
public class MessengerService extends Service {
    /** Command to the service to display a message */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    class IncomingHandler extends Handler {//定義一個(gè)Handler
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());//用Handler創(chuàng)建一個(gè)Messenger

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();//返回用Messenger創(chuàng)建的IBinder
    }
}

//客戶端:
public class ActivityMessenger extends Activity {
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean mBound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);//用IBinder創(chuàng)建Messenger
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false;
        }
    };

    public void sayHello(View v) {
        if (!mBound) return;
        // Create and send a message to the service, using a supported 'what' value
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {//記得Catch Exception
            e.printStackTrace();
        }
    }

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

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to the service
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE); //實(shí)際應(yīng)用中,這里應(yīng)該是隱式intent
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}

AIDL方式

  1. 服務(wù)端

    • 創(chuàng)建AIDL
      • 創(chuàng)建接口定義和方法簽名
      • 可識(shí)別的數(shù)據(jù)類型包括基本類型(int,long,boolean),String,CharSequence,List(支持泛型,對(duì)端接收到的總是一個(gè)arrayList),Map接口(不支持泛型,對(duì)端接收到的總是一個(gè)HashMap),List和Map必須加in/out/inout參數(shù)(in:參數(shù)會(huì)傳輸?shù)椒?wù)端,out:參數(shù)只是用來獲取輸出值,沒有傳輸,inout:兩者結(jié)合)
      • 只能有方法,不能有靜態(tài)域
    • 實(shí)現(xiàn)接口,SDK自動(dòng)生成名為Stub的抽象函數(shù)(派生于Binder),我們需要派生這個(gè)Stub類并實(shí)現(xiàn)它的抽象方法
      • 調(diào)用通常是以同步方式執(zhí)行,所以注意不要在調(diào)用方的主線程調(diào)用,可能引起調(diào)用方的ANR
      • 在服務(wù)端發(fā)出的exception并不會(huì)被返回到調(diào)用方。
        實(shí)現(xiàn)服務(wù),在onBind()中將stub的實(shí)例返回去
  2. 客戶端

    • 也要導(dǎo)入AIDL
    • 調(diào)用bind之后,在onServiceConnected()中用IRemoteService.Stub.asInterface(service)將Binder轉(zhuǎn)換為接口,就可以直接使用了
  3. 本地調(diào)用發(fā)生在與調(diào)用方相同的線程,遠(yuǎn)程調(diào)用發(fā)生在一個(gè)系統(tǒng)維護(hù)的線程池中(這里,跟Service在主線程上運(yùn)行是有出入的)

  4. example:
    AIDL:

package com.example.testservice;

interface ITestAidl {
    List<String> testListGeneric();
    List testListNoGeneric();//支持泛型List
    //List testListWithGeneric1(in List param); //不支持非泛型參數(shù)
    List testListWithGeneric(in List<String> param);
    //Map<String,String> testMap1(); //不支持泛型Map
    //Map testMap(out Map param);//Map做參數(shù),gen里面會(huì)報(bào)錯(cuò),原因應(yīng)該是因?yàn)椴恢С址欠盒蛥?shù)
    Map testMap(String Param);
    
    List testIn(in List<String> param);//in:參數(shù)會(huì)被輸送到服務(wù)端
//@Override public java.util.List testIn(java.util.List<java.lang.String> param) throws android.os.RemoteException
//{
//android.os.Parcel _data = android.os.Parcel.obtain();
//android.os.Parcel _reply = android.os.Parcel.obtain();
//java.util.List _result;
//try {
//_data.writeInterfaceToken(DESCRIPTOR);
//_data.writeStringList(param);
//mRemote.transact(Stub.TRANSACTION_testIn, _data, _reply, 0);
//_reply.readException();
//java.lang.ClassLoader cl = (java.lang.ClassLoader)this.getClass().getClassLoader();
//_result = _reply.readArrayList(cl);
//}
//finally {
//_reply.recycle();
//_data.recycle();
//}
//return _result;
//}
    List testOut(out List<String> param);//out:參數(shù)只是用來獲取輸出值
//{
//android.os.Parcel _data = android.os.Parcel.obtain();
//android.os.Parcel _reply = android.os.Parcel.obtain();
//java.util.List _result;
//try {
//_data.writeInterfaceToken(DESCRIPTOR);
//mRemote.transact(Stub.TRANSACTION_testOut, _data, _reply, 0);
//_reply.readException();
//java.lang.ClassLoader cl = (java.lang.ClassLoader)this.getClass().getClassLoader();
//_result = _reply.readArrayList(cl);
//_reply.readStringList(param);
//}
//finally {
//_reply.recycle();
//_data.recycle();
//}
//return _result;
//}
    List testInOut(inout List<String> param);//參數(shù)會(huì)被傳輸,處理后成為輸出值
//{
//android.os.Parcel _data = android.os.Parcel.obtain();
//android.os.Parcel _reply = android.os.Parcel.obtain();
//java.util.List _result;
//try {
//_data.writeInterfaceToken(DESCRIPTOR);
//_data.writeStringList(param);
//mRemote.transact(Stub.TRANSACTION_testInOut, _data, _reply, 0);
//_reply.readException();
//java.lang.ClassLoader cl = (java.lang.ClassLoader)this.getClass().getClassLoader();
//_result = _reply.readArrayList(cl);
//_reply.readStringList(param);
//}
//finally {
//_reply.recycle();
//_data.recycle();
//}
//return _result;
//}
}

Service:

package com.example.testservice;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class SampleService extends Service {

    @Override
    public IBinder onBind(Intent arg0) {
        return mBinder;
    }

    private ITestAidl.Stub mBinder = new ITestAidl.Stub() {

        @Override
        public List testOut(List<String> param) throws RemoteException {
            for (String s : param) {
                Log.i("TestAIDL", "Before manipulate,param is:" + s);
            }
            param.add("5");
            param.add("6");
            param.add("7");
            return param;
        }

        @Override
        public Map testMap(String Param) throws RemoteException {
            Map<Integer, String> myMap = new Hashtable<Integer, String>();
            myMap.put(1, Param);
            myMap.put(2, Param + " " + Param);
            return myMap;
        }

        @Override
        public List testListWithGeneric(List<String> param)
                throws RemoteException {
        for (String s : param) {
                Log.d("TestAIDL", "Received:" + s);
        }
            return param;
        }

        @Override
        public List testListNoGeneric() throws RemoteException {
            List<String> myList = new ArrayList<String>();
            myList.add("A");
            myList.add("B");
            return myList;
        }

        @Override
        public List<String> testListGeneric() throws RemoteException {
            List<String> myList = new ArrayList<String>();
            myList.add("A");
            myList.add("B");
            return myList;
        }

        @Override
        public List testInOut(List<String> param) throws RemoteException {
            for (String s : param) {
                Log.i("TestAIDL", "Before manipulate,param is:" + s);
            }
            param.add("5");
            param.add("6");
            param.add("7");
            return param;
        }

        @Override
        public List testIn(List<String> param) throws RemoteException {
            for (String s : param) {
                Log.i("TestAIDL", "Before manipulate,param is:" + s);
            }
            param.add("5");
            param.add("6");
            param.add("7");
            return param;
        }
    };
}

Client:

package com.example.testserviceclient;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;

import com.example.testservice.ITestAidl;
import com.example.zzp.IMyinterface;

public class TestServiceClient extends Activity {
    public static final String ActionName = "com.zzp.test.TESTSERVICE";
    public static final String ActionNameUseJar = "com.zzp.test.USEJAR";
    private ITestAidl myService;
    private IMyinterface myJarService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ttest_service);

    }

    @Override
    protected void onStart() {
        bindService(new Intent(ActionName), myConnection,
                Context.BIND_AUTO_CREATE);
        bindService(new Intent(ActionNameUseJar), myJarConnection,
                Context.BIND_AUTO_CREATE);
        super.onStart();
    }

    @Override
    protected void onStop() {
        unbindService(myConnection);
        unbindService(myJarConnection);
        super.onStop();
    }

    private ServiceConnection myConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            return;
        }

        @Override
        public void onServiceConnected(ComponentName arg0, IBinder arg1) {
            myService = ITestAidl.Stub.asInterface(arg1);
        }
    };
    private ServiceConnection myJarConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            return;
        }

        @Override
        public void onServiceConnected(ComponentName arg0, IBinder arg1) {
            myJarService = (IMyinterface) arg1;
        }
    };
    public void onTestLG(View view) {
        try {
            List<String> myList = myService.testListGeneric();
            for (String s : myList) {
                Log.d("TestAIDL-Client", "Test List Generic:" + s);
                // D/TestAIDL-Client(20810): Test List Generic:A
                // D/TestAIDL-Client(20810): Test List Generic:B
            }
        } catch (RemoteException e) {
            Log.e("TestAIDL-Client", e.getMessage());
            e.printStackTrace();
        }

    }

    public void onTestLNG(View view) {
        try {
            // List<String> myList = myService.testListNoGeneric();
            List myList = myService.testListNoGeneric();
            for (Object s : myList) {
                Log.d("TestAIDL-Client",
                        "Test List Non Generic:" + s.toString());
                // D/TestAIDL-Client(25015): Test List Non Generic:A
                // D/TestAIDL-Client(25015): Test List Non Generic:B
            }
        } catch (RemoteException e) {
            Log.e("TestAIDL-Client", e.getMessage());
            e.printStackTrace();
        }
    }

    public void TestLwG(View view) {
        try {
            // List<String> myList = myService.testListNoGeneric();
            ArrayList<String> param = new ArrayList<String>();
            param.add("Client-A");
            param.add("Client-B");
            List myList = myService.testListWithGeneric(param);
            for (Object s : myList) {
                Log.d("TestAIDL-Client",
                        "Test List With Generic:" + s.toString());
                // D/TestAIDL(27513): Received:Client-A
                // D/TestAIDL(27513): Received:Client-B
                // D/TestAIDL-Client(27500): Test List With Generic:Client-A
                // D/TestAIDL-Client(27500): Test List With Generic:Client-B
            }
        } catch (RemoteException e) {
            Log.e("TestAIDL-Client", e.getMessage());
            e.printStackTrace();
        }
    }

    public void TestM(View view) {
        try {
            Map<Integer, String> myMap = myService.testMap("ABC");
            for (Entry<Integer, String> s : myMap.entrySet()) {
                Log.d("TestAIDL-Client",
                        "Test Map:" + s.getKey() + "_" + s.getValue());
                // D/TestAIDL-Client(29739): Test Map:1_ABC
                // D/TestAIDL-Client(29739): Test Map:2_ABC ABC
            }
        } catch (RemoteException e) {
            Log.e("TestAIDL-Client", e.getMessage());
            e.printStackTrace();
        }
    }

    public void TestIn(View view) {
        try {
            // List<String> myList = myService.testListNoGeneric();
            ArrayList<String> param = new ArrayList<String>();
            param.add("Client-A");
            param.add("Client-B");
            for (String s : param) {
                Log.d("TestAIDL-Client", "Test In, param:" + s.toString());
            }

            List myList = myService.testIn(param);

            for (String s : param) {
                Log.d("TestAIDL-Client", "Test In, param:" + s.toString());
            }

            for (Object s : myList) {
                Log.d("TestAIDL-Client",
                        "Test In, return value:" + s.toString());

            }
            // D/TestAIDL-Client(31223): Test In, param:Client-A
            // D/TestAIDL-Client(31223): Test In, param:Client-B
            // I/TestAIDL(29511): Before manipulate,param is:Client-A
            // I/TestAIDL(29511): Before manipulate,param is:Client-B
            // D/TestAIDL-Client(31223): Test In, param:Client-A
            // D/TestAIDL-Client(31223): Test In, param:Client-B
            // D/TestAIDL-Client(31223): Test In, return value:Client-A
            // D/TestAIDL-Client(31223): Test In, return value:Client-B
            // D/TestAIDL-Client(31223): Test In, return value:5
            // D/TestAIDL-Client(31223): Test In, return value:6
            // D/TestAIDL-Client(31223): Test In, return value:7
        } catch (RemoteException e) {
            Log.e("TestAIDL-Client", e.getMessage());
            e.printStackTrace();
        }
    }

    public void TestOut(View view) {
        try {
            // List<String> myList = myService.testListNoGeneric();
            ArrayList<String> param = new ArrayList<String>();
            param.add("Client-A");
            param.add("Client-B");
            for (String s : param) {
                Log.d("TestAIDL-Client", "Test Out, param:" + s.toString());
            }

            List myList = myService.testOut(param);

            for (String s : param) {
                Log.d("TestAIDL-Client", "Test Out, param:" + s.toString());
            }

            for (Object s : myList) {
                Log.d("TestAIDL-Client",
                        "Test Out, return value:" + s.toString());

            }
            // D/TestAIDL-Client( 2359): Test Out, param:Client-A
            // D/TestAIDL-Client( 2359): Test Out, param:Client-B
            // 這里,服務(wù)端并沒有收到param
            // D/TestAIDL-Client( 2359): Test Out, param:5
            // D/TestAIDL-Client( 2359): Test Out, param:6
            // D/TestAIDL-Client( 2359): Test Out, param:7
            // D/TestAIDL-Client( 2359): Test Out, return value:5
            // D/TestAIDL-Client( 2359): Test Out, return value:6
            // D/TestAIDL-Client( 2359): Test Out, return value:7
        } catch (RemoteException e) {
            Log.e("TestAIDL-Client", e.getMessage());
            e.printStackTrace();
        }
    }

    public void TestInOut(View view) {
        try {
            // List<String> myList = myService.testListNoGeneric();
            ArrayList<String> param = new ArrayList<String>();
            param.add("Client-A");
            param.add("Client-B");
            for (String s : param) {
                Log.d("TestAIDL-Client", "Test InOut, param:" + s.toString());
            }

            List myList = myService.testInOut(param);

            for (String s : param) {
                Log.d("TestAIDL-Client", "Test InOut, param:" + s.toString());
            }

            for (Object s : myList) {
                Log.d("TestAIDL-Client",
                        "Test InOut, return value:" + s.toString());

            }
            // D/TestAIDL-Client( 2359): Test InOut, param:Client-A
            // D/TestAIDL-Client( 2359): Test InOut, param:Client-B
            // I/TestAIDL(29511): Before manipulate,param is:Client-A
            // I/TestAIDL(29511): Before manipulate,param is:Client-B
            // D/TestAIDL-Client( 2359): Test InOut, param:Client-A
            // D/TestAIDL-Client( 2359): Test InOut, param:Client-B
            // D/TestAIDL-Client( 2359): Test InOut, param:5
            // D/TestAIDL-Client( 2359): Test InOut, param:6
            // D/TestAIDL-Client( 2359): Test InOut, param:7
            // D/TestAIDL-Client( 2359): Test InOut, return value:Client-A
            // D/TestAIDL-Client( 2359): Test InOut, return value:Client-B
            // D/TestAIDL-Client( 2359): Test InOut, return value:5
            // D/TestAIDL-Client( 2359): Test InOut, return value:6
            // D/TestAIDL-Client( 2359): Test InOut, return value:7
        } catch (RemoteException e) {
            Log.e("TestAIDL-Client", e.getMessage());
            e.printStackTrace();
        }
    }

    // public void TestUseJar(View view) {
    // Log.d("TestAIDL-Client", "Use Jar:" + myJarService.test());
    // Log.d("TestAIDL-Client", "Static value:" + myJarService.DEFINE);
    // Hashtable<Integer, String> param = new Hashtable<Integer, String>();
    // param.put(5, "壹");
    // param.put(6, "貳");
    //
    // Hashtable<Integer, String> myTable = myJarService.testGenericMap(param);
    // for (Entry<Integer, String> s : myTable.entrySet()) {
    // Log.d("TestAIDL-Client",
    // "Use Jar Map:" + s.getKey() + "_" + s.getValue());
    // }
    //
    // }
}

附:進(jìn)程優(yōu)先級(jí)

當(dāng)系統(tǒng)決定殺掉一個(gè)進(jìn)程的時(shí)候,會(huì)按照進(jìn)程優(yōu)先級(jí)的從低到高來決定先殺哪個(gè)。

  • 前臺(tái)
    • 擁有Activity并用戶正在交互(onResume)
    • 擁有服務(wù)且服務(wù)與一個(gè)前臺(tái)頁面綁定
    • 擁有服務(wù),且通過startForeground()調(diào)用
    • 正在執(zhí)行服務(wù)的生命周期(onCreate等)
    • 廣播正在執(zhí)行onReceive
  • 可見
    • 頁面已暫停
    • 服務(wù)綁定到前臺(tái)或可見頁面
  • 服務(wù)進(jìn)程
    • 含有用Start方式啟動(dòng)的服務(wù)
  • 后臺(tái)進(jìn)程
    • 頁面已不再可見(onStop被調(diào)用)
    • LRU (least recently used) list, 最早停止的最早kill
  • 空進(jìn)程
    • 不含有效組件,只為緩存

轉(zhuǎn)載請(qǐng)注明出處。

image

更多視頻教程請(qǐng)?jiān)?a target="_blank">網(wǎng)易云課堂搜索黑山老雕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容