Android Service的使用

2019-12-19  本文已影响0人  黑山老雕

类型和区别

创建一个新的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 &前台服务

Bounded Service

创建bounded service的三种方式

扩展Binder类方式

//服务端:
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方式

//服务端:
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());
    // }
    //
    // }
}

附:进程优先级

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


转载请注明出处。

image

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

上一篇下一篇

猜你喜欢

热点阅读