您的位置:首页 > 移动开发 > Android开发

转载 android service 使用以及aidl使用

2015-11-16 15:29 363 查看
service

将android:exported属性声明为false,则无论你在manifest文件中声明了什么样的过滤条件,这个service都只能为你自己私用。

1:service的启动方式

service 是一个在后台运行的服务。你所启动的这个service所做得工作最好在另一个线程中做。因为这个service的线程的工作将阻塞调用它的线程。

在service的onCreate函数中你可能需要启动一个线程来完成service需要干的工作

public void onCreate() {

// Start up the thread running the service. Note that we create a

// separate thread because the service normally runs in the process's

// main thread, which we don't want to block. We also make it

// background priority so CPU-intensive work will not disrupt our UI.

HandlerThread thread = new HandlerThread("ServiceStartArguments",

Process.THREAD_PRIORITY_BACKGROUND);

thread.start();

// Get the HandlerThread's Looper and use it for our Handler

mServiceLooper = thread.getLooper();

mServiceHandler = new ServiceHandler(mServiceLooper);

}

创建和启动一个service有两种方式

Intent in = new Intent(***);

startService(in) 和 bindService(in)。

与上面相对应,停止一个service也有两种方式

stopService(in) 和 unbindService(in)。

但是不管一个service是如何启动的,它基本都是可以被客户端bind的,除非你禁止他这个功能。所以不要把start和bind看的过分分离

如果是本地的service 则 Intent in = new Intent(this,LocalService.class)。同时那个service要在manifest文件中标明自己的name

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

如果是非本地的service 则在Intent中指明就可以了Intent in= new Intent("com.test.A") 与此同时那个非本地的service也要在manifest文件中申明自己的name和intent-filter

<service android:name = ".serviceA">

<intent-filter>

<action android:name="com.test.A"/>

<category android:name="android.intent.category.DEFAULT" />

</intent-filter>

</service>

2:使用startService 和 stopService

这种启动和停止方式是比较简单的。只需要在调用Activity中直接写上就可以了。

2.1service客户端代码

调用service的客户端的activity的代码:

package com.D_activity;

import android.app.Activity;

import android.content.Intent;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

public class D_activity extends Activity {

Button b;

private boolean running = false;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

//设置一个按钮来开启和关闭服务

b=(Button)findViewById(R.id.button);

}

@Override

protected void onResume() {

//指定一个Intent

final Intent in = new Intent("com.test.A");

super.onResume();

b.setOnClickListener(new OnClickListener(){

@Override

public void onClick(View v) {

if(running){

running = false;

//关闭服务

stopService(in);

b.setText("start ");

}

else{

running = true;

//开启服务

startService(in);

b.setText("stop");

}

}

});

}

}

2.2 被startService()调用的service 的代码:

通过startService启动的service在service的生命周期中将调用:onCreate()->onStartCommand()->onDestory()。

onCreate 仅仅在第一次创建这个service的时候调用。

onStartCommand会在你使用startService()后调用,并且必须返回一个Int值用来表示这个service被系统杀掉后该如何处理。数值如下:

START_NOT_STICKY:系统将不再重新创建service

START_STICKY:系统将重现创建service并调用onStartCommand()但不会使用上一次的Intent。

START_REDELIVER_INTENT:系统将重现创建service并调用onStartCommand()并且会使用上一次的Intent。

如果你只实现了onStartCommand()那么由于无法onBind()所以这将是你的service唯一与外界沟通的地方

onDestory会在你使用stopSerivce的时候调用。

以下代码将实现一个每5秒打印系统时间的service,多半代码都是从文档中直接拿过来的。

package com.A_s;

public class serviceA extends Service {

private boolean flag =true;

private Looper mServiceLooper;

private ServiceHandler mServiceHandler;

// Handler that receives messages from the thread

private final class ServiceHandler extends Handler {

public ServiceHandler(Looper looper) {

super(looper);

}

@Override

public void handleMessage(Message msg) {

// Normally we would do some work here, like download a file.

// For our sample, we just sleep for 5 seconds.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

while(flag){

synchronized (this) {

try {

Log.i("TEST","A :"+sdf.format(System.currentTimeMillis()));

wait(5*1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

// Stop the service using the startId, so that we don't stop

// the service in the middle of handling another job

stopSelf(msg.arg1);

}

}

@Override

public void onCreate() {

// Start up the thread running the service. Note that we create a

// separate thread because the service normally runs in the process's

// main thread, which we don't want to block. We also make it

// background priority so CPU-intensive work will not disrupt our UI.

HandlerThread thread = new HandlerThread("ServiceStartArguments",

Process.THREAD_PRIORITY_BACKGROUND);

thread.start();

// Get the HandlerThread's Looper and use it for our Handler

mServiceLooper = thread.getLooper();

mServiceHandler = new ServiceHandler(mServiceLooper);

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

// For each start request, send a message to start a job and deliver the

// start ID so we know which request we're stopping when we finish the job

Message msg = mServiceHandler.obtainMessage();

msg.arg1 = startId;

mServiceHandler.sendMessage(msg);

// If we get killed, after returning from here, restart

return START_STICKY;

}

@Override

public IBinder onBind(Intent intent) {

// We don't provide binding, so return null

return null;

}

@Override

public void onDestroy() {

Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();

flag =false;

}

}

Manifest文件:

<service android:name = ".serviceA">

<intent-filter>

<action android:name="com.test.A"/>

<category android:name="android.intent.category.DEFAULT" />

</intent-filter>

</service>

3:使用bindService和 unbindService

这种方式启动的service 生命周期中将调用:onCreate()->onBind()->onUnbind()->onDestory()。

在service中与之前startService最不同的一点是,这次service不再使用onStartCommand而是使用onBind.

客户端通过bindService去连接service的必须在自身实现ServiceConnection接口,用来处理回传的IBind

只有Activity provider service可以绑定到service上 但是broadcastReceiver不能

基于你的需求,你可以在activity的 onstart->onstop区间 或者 oncreate()->onDestroy()进行绑定和解绑定,但是千万不要再OnResume()->OnPause()进行,因为他会导致activity的频繁切换时频繁绑定和解绑定

@Override

public IBinder onBind(Intent intent) {

// We don't provide binding, so return null

Toast.makeText(this, "service starting in onBind", Toast.LENGTH_SHORT).show();

Message msg = mServiceHandler.obtainMessage();

mServiceHandler.sendMessage(msg);

return IBind;

}

3.1使用bindService的客户端的代码如下

这次的Activity明显比之前使用startService的Activity多了一点东西,就是多了ServiceConnection类。当bindService完成时,service会通过ServiceConnection类回调相关接口和回传IBind

当最后一个客户端调用unBind后,service将被系统销毁,除非service是被startService启动的

package com.C_activity;

public class C_activity extends Activity {

Button b;

private boolean running = false;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

b=(Button)findViewById(R.id.button);

}

@Override

protected void onResume() {

final Intent in = new Intent("com.test.E");

super.onResume();

b.setOnClickListener(new OnClickListener(){

@Override

public void onClick(View v) {

if(running){

running = false;

unbindService(sc);

b.setText("start ");

}

else{

running = true;

//bindService方法的最后一个参数有其特定的意义,最好找文档确定自己需要哪种

bindService(in, sc, 1);

b.setText("stop");

}

}

});

}

private ServiceConnection sc = new ServiceConnection(){

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

//你可以在这个地方处理service回传的IBinder,如果符合你的需求的话,这个IBinder甚至可以继承成你自己的IBinder,更方便操作。

}

@Override

public void onServiceDisconnected(ComponentName name) {

}

};

}

4:利用aidl 远程调用service

当service 不是本地的服务,也就不能通过onServiceConnected中的IBinder来强制转换成相应服务类来使用service提供的一些方法。这时就需要使用aidl了。

直观的去看,远程服务如果能够被操作,也需要提供一个操作的接口,而这个接口不光在服务器端实现,同时在客户端也需要知道调用和使用的方式;因此我们需要定义aidl文件来描述这么一个服务,也就是通过双方共享一个aidl文件的方式来共享一个接口。

在aidl里面定义了这个接口的内容之后, android的IDE帮助编译自动生成一个相应名字的java文件。这个java里面生成一个接口:test_aidl (extends android.os.IInterface) ,

同时,最主要的,里面有个桩: public static abstract class Stub extends android.os.Binder implements test_aidl

比如我写了一个叫test_aidl.aidl的文件 内容如下:

package com.E_s;

interface test_aidl{

int getCount();

}

那么在工程的gen目录下会自动生成一个test_aidl.java文件。然后在service中你就可以使用并实现这个接口中的方法。

private final test_aidl.Stub IBind = new test_aidl.Stub() {

@Override

public int getCount() throws RemoteException {

// TODO Auto-generated method stub

return i;

}

};

4.1 使用aidl的service端的全部代码如下:

package com.E_s;

public class serviceA extends Service {

private boolean flag =true;

private Looper mServiceLooper;

private ServiceHandler mServiceHandler;

public static int i = 0;

// Handler that receives messages from the thread

private final class ServiceHandler extends Handler {

public ServiceHandler(Looper looper) {

super(looper);

}

@Override

public void handleMessage(Message msg) {

// Normally we would do some work here, like download a file.

// For our sample, we just sleep for 5 seconds.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

while(flag){

synchronized (this) {

try {

i++;

Toast.makeText(serviceA.this, "E_s", Toast.LENGTH_SHORT).show();

Log.i("liyufei","E(A) :"+sdf.format(System.currentTimeMillis()));

wait(5*1000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

// Stop the service using the startId, so that we don't stop

// the service in the middle of handling another job

// stopSelf(msg.arg1);

}

}

@Override

public void onCreate() {

// Start up the thread running the service. Note that we create a

// separate thread because the service normally runs in the process's

// main thread, which we don't want to block. We also make it

// background priority so CPU-intensive work will not disrupt our UI.

HandlerThread thread = new HandlerThread("ServiceStartArguments",

Process.THREAD_PRIORITY_BACKGROUND);

thread.start();

// Get the HandlerThread's Looper and use it for our Handler

mServiceLooper = thread.getLooper();

mServiceHandler = new ServiceHandler(mServiceLooper);

}

@Override

public IBinder onBind(Intent intent) {

Toast.makeText(this, "service starting in onBind", Toast.LENGTH_SHORT).show();

Message msg = mServiceHandler.obtainMessage();

mServiceHandler.sendMessage(msg);

return IBind;

}

private final test_aidl.Stub IBind = new test_aidl.Stub() {

@Override

public int getCount() throws RemoteException {

return i;

}

};

@Override

public void onDestroy() {

Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();

flag =false;

}

}

在客户端,你首先要在客户端的工程中也创建相应的包名和aidl文件。比如将文中的test_aidl.aidl也放入客户端的com.E_s包中。然后客户端中也会自动生成一个test_aidl.java文件。

然后就只需要将之前的使用bindService的客户端代码中的ServiceConnection方法中添加些东西就好了。

test_aidl testAidl;

private ServiceConnection sc = new ServiceConnection(){

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

testAidl = test_aidl.Stub.asInterface(service);

}

@Override

public void onServiceDisconnected(ComponentName name) {

testAidl = null;

}

};

然后你就可以使用这个ta就可以直接操作service中的方法了。比如testAidl.getCount();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: