您的位置:首页 > 其它

Activity调用Service里的方法

2015-03-12 16:58 363 查看
Service是不能被实例化的,那么我们如果想调用里边的方法,该怎样进行呢?

首先看一个Serviece类

public class SingService extends Service{

@Override
public IBinder onBind(Intent intent) {
// TODO 自动生成的方法存根
return null;
}
@Override
public void onCreate() {
// TODO 自动生成的方法存根
super.onCreate();
System.out.print("服务启动,开始唱歌了");
}
@Override
public void onDestroy() {
// TODO 自动生成的方法存根
super.onDestroy();
System.out.print("服务结束,停止唱歌了");
}
//自定义的方法
public void ChangeSong(String songName){
Toast.makeText(getApplicationContext(), "切换歌曲", 0).show();
}

}
Activity的代码部分如下:由于这些方法都是按钮的点击事件,所以传入参数View(例如在XML文件中android:click = "start")

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/*
* 开启服务
* */
public void start(View view){
Intent intent = new Intent(this, SingService.class);
//采用api创建服务,服务对象是被系统(Android 框架)new 出来的
startService(intent);
}
/*
* 停止服务
* */
public void stop(View view){
Intent intent = new Intent(this, SingService.class);
stopService(intent);
}
/*
* 调用服务里的方法,换首歌,由于Service是系统创建的,我们不能NEW对象调用方法
* */
public void change(View view){
//由于系统框架在创建服务的时候,会创建与之对应的上下文,下面的代码是错误的
//		SingService service = new SingService();
//		service.ChangeSong("月亮之上");

}
}
那么我们怎样才能调用Service里的方法呢?可以采用代理人模式,不直接调用,而是通过与之有关系的代理人来实现。

我们启动Service,除了StartService之外,还可以通过bindService的方法,得到代理人对象。

首先看Service类的写法有什么不一样

public class SingService extends Service{

@Override
<strong>//步骤二:服务在成功绑定的时候会调动onBind方法,返回一个IBinder对象</strong>
<span style="font-size:12px;">	</span><span style="font-size:14px;"><span style="color:#ff0000;">public IBinder onBind(Intent intent) {
// 当服务被成功绑定的时候,系统自动调用该方法
System.out.print("服务成功被绑定");
//返回自定义的代理人对象,这个很关键
return new MyBinder();
}</span>

<span style="color:#ff0000;">	public class MyBinder extends Binder{
//简介的利用代理人,调用了唱歌的方法
<strong>public  void CallChangeSong(String name){
ChangeSong(name);</strong>
}
}</span>	</span>
@Override
public void onCreate() {
// TODO 自动生成的方法存根
super.onCreate();
System.out.print("服务启动,开始唱歌了");
}
@Override
public void onDestroy() {
// TODO 自动生成的方法存根
super.onDestroy();
System.out.print("服务结束,停止唱歌了");
}
//自定义的方法
public void ChangeSong(String songName){
Toast.makeText(getApplicationContext(), "切换歌曲", 0).show();
}
}
Activity里的写法:

public class MainActivity extends Activity {
<strong>//步骤四:在Activity里面得到服务IBinder对象的引用</strong>
private SingService.MyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void change(View view){
<strong>//步骤五:利用iBinder对象间接的调用了服务里的方法</strong>
myBinder.CallChangeSong("月亮之上");
}

<strong>//步骤一:采用绑定服务的方式开启服务</strong>
public void bind(View view){
Intent intent = new Intent(this, SingService.class);
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
}

//建立一个内部类,代理人
private class MyConn implements ServiceConnection{
//在服务被成功绑定时候调用的方法
@Override
public void onServiceConnected(ComponentName name,
IBinder service) {
System.out.println("把代理人返回来了");
<strong>//第三步:服务返回的IBinder对象会被传递给myConn的回调方法</strong>
myBinder = (MyBinder) service;

}
//在服务失去绑定时候调用的方法,正常情况下不会被调用,只有在进程异常终止时候才会调用。
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO 自动生成的方法存根

}

}

}
整个的流程如下:



但是在实际的开发中,我们不可能这么直接去写,把代理人写在Service里,那肯定是不行的,而且不能直接定义成public让外部去访问,我们通常是建立一个接口,通过暴露接口的方式来实现。

public interface Iservice {
public void callChangeSong(String name);
}
单独写一个接口,统一规范作用

在Service中,把MyBinder类去实现这个接口

private class MyBinder extends Binder implements Iservice{
@Override
public void callChangeSong(String name) {
// TODO 自动生成的方法存根
ChangeSong(name);
}
}


在Activity中做如下修改:

private Iservice myBinder;
myBinder = (Iservice) service;


如果我们没有绑定服务,那么Activity退出了,服务还在,但是如果绑定了,那么Activity退出,服务跟着也马上退出。

服务的混合开启:

需求:既要想保证服务长期在后台运行,又想去调用服务里的方法,怎么办呢?

技巧:1、先开启服务——这样就可以保证服务长期运行(不绑定) 2、绑定服务——这样就可以调用里边的方法了

服务只会被创建一次,也就是当我们如果先开启了服务,会执行OnCreate方法,当再绑定服务的时候,onCreate方法不会再执行,直接执行onBind方法。

注意事项:

当我们绑定服务了之后,如果直接退出,会报出异常的错误,为什么呢?因为我们绑定了服务,直接退出会显示异常,怎样解决呢?也就是在我们退出的时候,要把绑定的服务解除掉。

定义一个方法:

//解除绑定服务的方法
public void unBind(View view){
unbindService(conn);
}
这时候在Service中会调用onUnbind方法,如下:

public boolean onUnbind(Intent intent) {
// TODO 自动生成的方法存根
System.out.println("解除绑定");
return super.onUnbind(intent);
}


服务一旦被绑定,通过StopService方法是不能停止掉的,只能通过解绑之后,才能停止,服务先解绑,然后直接onDestory了,所以绑定了服务,记得要解绑。如果点击多次绑定服务,只会调用一次onBind方法,但是如果调用多次解绑方法,程序第一次会调用解绑,后边就会报错。

为了防止忘记解绑服务,我们通常在Activity的onDestory中调用解绑服务的方法,这样就能保证应用程序在退出的时候,自动把程序解绑掉,但是如果程序员比较勤奋,之前已经解绑过了,那如果再解绑就会报错,怎么办呢?通常情况下我们可以用try_catch方法包围解绑,这样就比较安全了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: