Activity调用Service里的方法

论坛 期权论坛 脚本     
匿名技术用户   2021-1-2 03:21   11   0

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方法包围解绑,这样就比较安全了。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP