美文网首页
Android Service的使用

Android Service的使用

作者: 黑山老雕 | 来源:发表于2019-12-19 18:00 被阅读0次

类型和区别

  • 特点:没有UI,后台运行
  • Started
    • 启动方式startSevice()
    • 一旦启动,在后台永远运行,除非主动停止或者被kill
    • 通常不返回值(可发一个PendingIntent, 用广播返回值)
  • Bound
    • 启动方式bindService()
    • 只要有应用绑定到它,就在运行。当没有应用绑定时,service被摧毁。
    • 多个应用可以绑定到一个bind service.
    • BroadcastReceiver不能绑定到服务
    • 可以返回值,以及做进程间通信(IPC)
  • 一个service可以同时实现onStartCommand()和onBind()
  • 注意:Service是在主线程上运行,不要进行耗时操作


    image.png

创建一个新的service

  1. 重写父类方法

    • onStartCommand(). 被startService()调用,需要用stopSelf() or stopService()手动停用
    • onBind(),当调用bindSerivce()的时候会调用,需要返回一个IBinder
    • onCreate(). 一次性,如service已经在运行,则不再调用
    • onDestroy(). 前台服务>绑定到活动的服务>后台服务>长时间运行的后台服务. 服务会被kill,当有资源时,会尝试恢复。对于started服务,需要考虑当系统自动恢复时的处理。这根据onStartCommand()时的返回值有所不同:
      • START_STICKY, 重新启动时,传入的intent是null
      • START_STICKY_COMPATIBILITY, 不保证会重新调用onStartCommand()
      • START_NOT_STICKY, 不自动重启
      • START_REDELIVER_INTENT, 总是重新发送上次的intent
      • 可以通过flag来判断服务的性质START_FLAG_REDELIVERY, START_FLAG_RETRY
  2. 修改Manifest

    • android:enabled=["true" | "false"]
    • android:exported=[“true” | “false”],如果为false,只有相同userID的能访问。如果有intent filter,默认为true,如果没有,默认为false
    • android:icon="drawable resource“
    • android:isolatedProcess=[“true” | “false”], 为true时,将运行在独立进程中
    • android:label="string resource“
    • android:name="string“
    • android:permission=“string“,如果设置,只有拥有权限的才能访问
    • android:process=“string”

IntentService & Stop Service &前台服务

  • Intent Service
    • Service的子类,推荐的实现Started Service的方法。会自动为每个request创建worker thread.
    • 自动创建队列进行处理,不用担心线程冲突
    • 队列处理完毕自动stopSelf()
    • 自动为不可bind的(可以通过重写来实现可bind)
    • 只需要两点:
      • 构造函数中调用父类
      • 实现onHandleIntent()方法
    • 可以重写其它方法,但要记得返回父类函数
  • 停止Service
    • 当stop service时,如果多个request同时在处理,stopSelf()可能会把新发起的request结束掉,所以推荐使用stopSelf(int),这样会比较当前正在处理的request是不是结束的目标。
    • 记得stopSelf(),这是消耗系统资源的。
  • 前台Service
    • 提供必需的notification和id, 用startForeground(ONGOING_NOTIFICATION_ID, notification) 启动,用stopForeground(boolean removeNotification)停止
    • stopForeground并不停止服务,而只是会让前台notification消失

Bounded Service

创建bounded service的三种方式

  • 扩展Binder类,如果只是自己的应用内使用,用这种方式。
  • 使用Messenger,可实现IPC的最简单(?)的方法,线程安全,C/S端都用Handler来处理消息
  • 使用AIDL,优点是可以同时处理多个请求,对于大部分的app,Google并不推荐使用这种方式(但是在framework里面有很多)
    onBind()只在第一次绑定时执行一次,后续再绑定时返回第一次的Ibinder对象
    当调用服务的方法时,要捕获DeadObjectException异常,这个异常标明service不存在了
  • bindServices的flag
    • BIND_AUTO_CREATE
    • BIND_DEBUG_UNBIND,只用于调试。当设置时,以后的unbind请求的callstack会被保存
    • BIND_IMPORTANT,允许客户端把服务升级为“前台”优先级,一般只能升级到“可见”优先级
    • BIND_NOT_FOREGROUND,不允许把被绑定的服务升级为“前台”优先级。
    • BIND_ABOVE_CLIENT,道友比贫道更重要
    • BIND_ADJUST_WITH_ACTIVITY,如从activity发起,那么允许优先级随其可见性来调整
    • BIND_ALLOW_OOM_MANAGEMENT, 让拥有该服务的进程来自己管理优先级
    • BIND_WAIVE_PRIORITY,放弃调整优先级,让系统像对待普通应用一样对待

扩展Binder类方式

  • Service端
    • 实现一个Binder实例,其中包含可调用的方法或者其它包含可调用方法的类示例(包括当前的service类)
    • 在onBind()时返回该实例
  • Client端
    • 绑定时传入connection参数(一个ServiceConnection的实例),绑定是异步的,并不返回Binder
    • 在connection的onServiceConnected()方法中接收实例,并转换类型为Binder类型,然后调用需要的方法
    • 实现connection的onServiceDisconnected()方法,处理服务crash和被kill时的情况
  • 示例代码
//服务端:
public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();//实例化
    // 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 {//实现Binder,其中有可返回当前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时绑定service,绑定后立即返回,connection作为参数传入
                                                                   //绑定完成后,将会调用connection的onServiceConnected方法,客户端将在
                                                                   //那里接收Binder,并转型,然后得到要可调用方法的类,或者该Binder就包含可调方法
    }

    @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端
    • 创建Handler来处理消息
    • 用Handler创建一个Messenger
    • 在onBind()中返回Messenger创建的IBinder
  • Client端
    • 用得到的IBinder去创建Messenger
    • 用Messenger发消息指挥Service的Handler运行
    • (如需要回复),创建Client端的Messenger,在send()命令的replyTo参数中传入这个Messenger
  • Sample:
//服务端:
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 {//定义一个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创建一个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创建的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创建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); //实际应用中,这里应该是隐式intent
    }

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

AIDL方式

  1. 服务端

    • 创建AIDL
      • 创建接口定义和方法签名
      • 可识别的数据类型包括基本类型(int,long,boolean),String,CharSequence,List(支持泛型,对端接收到的总是一个arrayList),Map接口(不支持泛型,对端接收到的总是一个HashMap),List和Map必须加in/out/inout参数(in:参数会传输到服务端,out:参数只是用来获取输出值,没有传输,inout:两者结合)
      • 只能有方法,不能有静态域
    • 实现接口,SDK自动生成名为Stub的抽象函数(派生于Binder),我们需要派生这个Stub类并实现它的抽象方法
      • 调用通常是以同步方式执行,所以注意不要在调用方的主线程调用,可能引起调用方的ANR
      • 在服务端发出的exception并不会被返回到调用方。
        实现服务,在onBind()中将stub的实例返回去
  2. 客户端

    • 也要导入AIDL
    • 调用bind之后,在onServiceConnected()中用IRemoteService.Stub.asInterface(service)将Binder转换为接口,就可以直接使用了
  3. 本地调用发生在与调用方相同的线程,远程调用发生在一个系统维护的线程池中(这里,跟Service在主线程上运行是有出入的)

  4. example:
    AIDL:

package com.example.testservice;

interface ITestAidl {
    List<String> testListGeneric();
    List testListNoGeneric();//支持泛型List
    //List testListWithGeneric1(in List param); //不支持非泛型参数
    List testListWithGeneric(in List<String> param);
    //Map<String,String> testMap1(); //不支持泛型Map
    //Map testMap(out Map param);//Map做参数,gen里面会报错,原因应该是因为不支持非泛型参数
    Map testMap(String Param);
    
    List testIn(in List<String> param);//in:参数会被输送到服务端
//@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:参数只是用来获取输出值
//{
//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);//参数会被传输,处理后成为输出值
//{
//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
            // 这里,服务端并没有收到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());
    // }
    //
    // }
}

附:进程优先级

当系统决定杀掉一个进程的时候,会按照进程优先级的从低到高来决定先杀哪个。

  • 前台
    • 拥有Activity并用户正在交互(onResume)
    • 拥有服务且服务与一个前台页面绑定
    • 拥有服务,且通过startForeground()调用
    • 正在执行服务的生命周期(onCreate等)
    • 广播正在执行onReceive
  • 可见
    • 页面已暂停
    • 服务绑定到前台或可见页面
  • 服务进程
    • 含有用Start方式启动的服务
  • 后台进程
    • 页面已不再可见(onStop被调用)
    • LRU (least recently used) list, 最早停止的最早kill
  • 空进程
    • 不含有效组件,只为缓存

转载请注明出处。

image

更多视频教程请在网易云课堂搜索黑山老雕。

相关文章

网友评论

      本文标题:Android Service的使用

      本文链接:https://www.haomeiwen.com/subject/xucvnctx.html