Android--绑定服务调用服务的方法-阿里云开发者社区

开发者社区> 开发与运维> 正文

Android--绑定服务调用服务的方法

简介: 版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/51078622 Service按照其启动的方式,可分为两种:1、StartedStarted的Service,通过在Application里用startService(Intent intent)方法来启动。
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/51078622
Service按照其启动的方式,可分为两种:
1、Started
Started的Service,通过在Application里用startService(Intent intent)方法来启动。这种类型的Service一经启动,会在后面无休止地运行,即使启动它的Activity被Destroy掉。要停止此类型的Service,可在Service中调用stopSelf()或在Application中调用stopService(Intent intent),要不然就只能等Android系统在系统资源紧张的时候把它杀掉。

2、Bound

Bound的Service,通过在Application里调用bindService()方法来启动。该类型的Service与Application绑定在一起,一旦绑定的所有Application消失了,Android会Detroy掉该Service。也可以主动调用unbindService()方法来解绑Service。


有时候我们想在Activity中获知Service的状态,例如一个音乐播放器,Service负责音乐播放,Activity负责显示当前歌曲名和播放进度。

可以用Broadcast,这个也不失为一个解决方法。

但如果可以获取Service实例,那么就可以调用Service中自定义的一些方法来获取Service状态了。

首先要明确的是,第一种类型的Service是无能为力的。因为Activity与Service之间并没有相关联的接口,即使这个Service是在Activity里start的,一旦start,两者不再有关联。

一、本地Service调用。

如果Activity与Service在同一应用程序中,两者间的交互就属于本地Service调用。

可通过bindService实现,具体操作如下:

1、自定义子类MyService,继承Service类
2、在MyService类中,自定义内部类MyBinder,继承Binder类

在内部类中,根据需要交互的数据,创建一些方法,以便Activity可通过这些方法得到Service中的一些数据。或者干脆通过一个方法返回Service实例。

public class MyBinder extends Binder  
{  
public MyService getServiceInstance()  
{  
return MyService.this;  
}  
}  
3、在Service类中,new一个MyBinder私有成员,并在onBind()方法中return一个MyBinder实例。

之所以这样做,是因为Service一旦绑定,就会回调onBind()方法,并返回一个Binder对象给Activity。具体看下一个步骤。


4、在Activity中覆写ServiceConnection接口中的onServiceConnected(ComponentName name, IBinder service)方法,

其中的service参数就是MyService类中onBind()方法返回的MyBinder对象,调用MyBinder对象的自定义方法getServiceInstance()可得到Service实例。

下面是一个DEMO:

import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;

public class MainActivity extends Activity {

	MusicInterface mi;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, MusicService.class);
        //混合调用
        //为了把服务所在进程变成服务进程
        startService(intent);
        //为了拿到中间人对象
        bindService(intent, new MusicServiceConn(), BIND_AUTO_CREATE);
    }

    class MusicServiceConn implements ServiceConnection{

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			mi = (MusicInterface) service;
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			
		}
    	
    }

    //开始播放按钮
    public void play(View v){
    	mi.play();
    }
    //暂停播放按钮
    public void pause(View v){
    	mi.pause();
    }
}

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

public class MusicService extends Service{
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return new MusicController();
	}
	
	
	//必须继承binder,才能作为中间人对象返回
	class MusicController extends Binder implements MusicInterface{
		public void play(){
			MusicService.this.play();
		}
		public void pause(){
			MusicService.this.pause();
		}
	}
	
	public void play(){
		System.out.println("播放音乐");
	}
	
	public void pause(){
		System.out.println("暂停播放");
	}

	
}
public interface MusicInterface {

	void play();
	void pause();
}

二、跨进程Service调用

跨进程Service调用,即在当前应用程序中,调用另一个应用程序中的Service。

因为Android中,每个应用程序都运行于自己的进程中,拥有独立的Dalvik虚拟机实例,因而称为跨进程调用(Inter-Process Comunication)。

可通过AIDL服务来实现。

AIDL(Android Interface Definition Language),是Android定义的一种类似Java的语言。主要用于定义跨进程调用时,服务端跟客户端用于数据交互的接口。

AIDL服务并不支持所有的Java数据类型。它只支持以下的几种类型:
1、Java的简单类型(int, char, boolean等)。无需import
2、String和CharSequence。无需import
3、List和Map。无需import(应当注意的是:List和Map的元素类型必须是AIDL支持的)
4、AIDL自动生成的接口。需要import
5、实现android.os.Parcelable接口的类。需要import

建立简单的AIDL服务的步骤如下:
(一)服务端步骤:
1、在服务端创建AIDL文件IMyAidl.aidl
AIDL与Java代码很相近,示例代码如下:(注意:aidl文件后缀名为.aidl)

interface IMyAidl
{
void print();
}
创建完aidl文件后,ADT会自动调用aidl命令生成相应的Java文件。可查看gen文件夹下是否有一个名为IMyAidl.java的文件。如果没有,说明.aidl文件有误。

2、继承Service类,在子类中,将AIDL接口暴露出来。
这一步类似于本地Service调用,则通过onBind(Intent intent)方法返回一个IBinder对象。
示例代码如下:

public class MyService extends Service
{
private AidlBinder mBinder;
//Stub类是上一步骤中,aidl命令生成的Java代码中的一个类
//该类实现了IBinder接口和IMyAidl接口
//可以通过继承该类,然后在onBind()方法中返回AidlBinder对象
//如此一来,即可通过AidlBinder对象对AIDL文件中定义的方法进行调用
public class AidlBinder extends Stub
{
@Override
public void print()
{
System.out.println("Hello world!")//实现AIDL文件中的接口函数
}
}
@Override
public void onCreate()
{
mBinder = new AidlBinder();//启动服务时即创建Binder对象
}

@Override
public IBinder onBind(Intent intent)
{
return mBinder;//返回Binder对象,让客户端获得Binder对象
}
}
3、配置AndroidManifest.xml文件

<!-- 自定义访问Service所需的权限 -->
<permission android:protectLevel="normal" android:name="thomas.permission.AIDL_SERVICE"/>

<service android:name="com.thomas.aidlserver.MyService" android:exported="true"
android:permission="thomas.permission.AIDL_SERVICE">
<!-- IntentFilter属性是必不可少的 -->
<!-- 如此一来,客户端才能通过该action远程调用服务端的Service -->
<intent-filter>
<action android:name="com.thomas.aidlserver.action.AIDL_SERVICE"/>
</intent-filter>
</service>
(二)客户端步骤:
1、创建AIDL文件
客户端也要创建AIDL文件,而且是跟服务端完全一样的AIDL文件。
复制服务端AIDL文件即可。应当注意的是:AIDL文件的包名一定要跟服务端的一致。
如果客户端没有该包,应创建一个包,并将AIDL文件放到包下。

2、跨进程调用Service
客户端跨进程调用Service的方法与本地调用Service的方法差不多,也是通过bindService()。
应当注意的是,调用成功后,通过ServiceConnection接口中的onServiceConnected(ComponentName name, IBinder service)方法得到服务端onBind()方法传递过来的Binder对象。将该对象类型转化为AIDL文件中声明的接口类型,即可调用该接口中定义的方法。
示例代码如下:

private IMyAidl mAidl;
mServiceCon = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
//将IBinder类型转化为IMyAidl类型。
mAidl = IMyAidl.Stub.asInterface(service);
}
@Override
public void onServiceDisonnected(ComponentName name){}
}
//远程Service绑定,其中Intent的action参数是服务端在
//AndroidManifest.xml文件中<service>标签下的<intent-filter>指定的字符串
bindService(new Intent("com.thomas.aidlserver.action.AIDL_SERVICE"),
mServiceCon, Service.BIND_AUTO_CREATE);
mAidl.print();//调用AIDL文件中声明的方法

3、配置AndroidManifest.xml文件

<!-- 请求访问远程Service所需的权限,该权限定义于服务端的AndroidManifest.xml文件中 -->
<uses-permission android:name="thomas.permission.AIDL_SERVICE"/>








版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章