转载 android service 使用以及aidl使用

来源:互联网 发布:重庆大学电气工程 知乎 编辑:程序博客网 时间:2024/05/16 08:36


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();
0 0
原创粉丝点击