[android] 04_绑定服务的应用场景——调用服务内的方法

Android 4.0

绑定服务的应用场景——调用服务内的方法
访问服务内部方法,调用服务内部方法

绑定服务调用服务里面方法的流程:
1. 在activity 采用bindService方式开启服务...
 
2. 写一个实现类 MyConn implements ServiceConnection
 
3.  接口里面有一个方法onServiceConnected 在服务成功绑定的时候调用的方法
 
4.  在service代码 实现 onBind方法  返回一个IBinder接口的实现( 里面必须一个调用服务方法的api)
 
5.  在服务成功绑定的时候 服务里面返回的IBinder对象会传给 activity里面onServiceConnected 方法
 
6. 获取IBinder对象 中间人, 调用中间人的方法. 间接调用了服务里面的方法
小结:
在Activity中调用Service中的方法
①在Service内部写一个要被调用的方法 iAmAMethodInService()
②在Service内部写一个接口实现类IBinder或者Binder类子类,MyBinder
③在该类中写一个方法,用于调用Service内部的方法,callMethodInService()
④在Service的onBind()方法中返回该实现类的实例,return new MyBinder();
⑤在Activity的ServiceConnection实现类中的onServiceConnected()方法,在Service中onBind返回一个可用的IBinder后,该方法会被调用,这时,我们也就拿到了可以调用Service内方法的第三方工具了
⑥在需要的地方调用
核心代码:
MainActivity.java
package cn.zengfansheng.service;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import cn.zengfansheng.service.MyService.MyBinder;
public class MainActivity extends Activity {
    private ServiceConnection conn;
    private MyBinder myBinder;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    /**
     * 开启服务
     * @param view
     */
    public void start(View view) {
        Intent intent = new Intent(this, MyService.class);
        startService(intent);
    }

    /**
     * TODO 一、 在activity 采用bindService方式开启服务...
     * 绑定服务, 目的:为了获取到中间人, 间接的调用到服务里面的方法.
     * @param view
     */
    public void bind(View view) {
        Intent service = new Intent(this, MyService.class);
        conn = new MyConn();
        this.bindService(service, conn , Context.BIND_AUTO_CREATE);
    }

    // TODO 二、 写一个实现类 MyConn implements ServiceConnection
    private class MyConn implements ServiceConnection {
        // 服务被成功绑定的时候 调用的方法.如果service中onBind()方法返回为null,那么表示service和activity没有绑定成功,那么该方法是不会被执行的。
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            System.out.println("服务连接上来的。。。");
            // TODO 六、方法参数中的service就是Activity和Service连接的中间人
            if (service != null) {
                myBinder = (MyBinder) service;// 获取服务的代理对象
            }
        }
        // 服务异常终止时,失去连接的时候,会被调用,正常停止服务是不会被调用的
        @Override
        public void onServiceDisconnected(ComponentName name) {
            System.out.println("服务被异常终止了。。。");
        }
    }
    /**
     * 解除绑定服务
     * @param view
     */
    public void unbind(View view) {
        if (conn != null) {
            this.unbindService(conn);// 间接调用服务里面的方法
            conn = null;
        }
    }
    
    /**
     * 调用服务内的方法
     * @param view
     */
    public void call(View view){
        // MyService myService = new MyService();
        // myService.iAmAMethodInService();
        // TODO 七、通过返回过来的中间人,调用Service类的方法
        myBinder.callMethodInService(5009);
    }
}

MyService.java
package cn.zengfansheng.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;

public class MyService extends Service {

    // TODO 三、该方法返回的就是服务和Activity的中间人对象, 当服务被成功绑定的时候 返回一个代理人对象.
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("service onBind()...");
        return new MyBinder();
    }

    /**
     * TODO 四、Service和Activity的中间人IBinder,代理人
     */

    public class MyBinder extends Binder {
        // TODO 五、提供一个API,调用Service类的方法
        public boolean callMethodInService(long money) {
            if (money > 5000) {
                iAmAMethodInService();
                return true;
            } else {
                System.out.println("这点钱还想打发我...");
                return false;
            }
        }
    }

    /**
     * 这是服务里面的一个方法.
     */

    public void iAmAMethodInService() {
        Toast.makeText(this, "我的service内的一个方法。。。", 0).show();
    }

    @Override
    public void onCreate() {
        System.out.println("service onCreate()....");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("service onStartCommand()...");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        System.out.println("service onDestroy()....");
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("service on Unbind()...");
        return super.onUnbind(intent);
    }
}
 结果:

安全隐患如果MyBinder中打麻将的方法不小心public后,拿到代理人对象都可以调用不安全
所以定义一个接口,对外暴露接口,接口中的方法才是要被暴露出去的
public interface IService {
    public boolean callMethodInService(long money);
}
修改后:
    private class MyBinder extends Binder implements IService {
        // TODO 五、提供一个API,调用Service类的方法
        public boolean callMethodInService(long money) {
            if (money > 5000) {
                iAmAMethodInService();
                return true;
            } else {
                System.out.println("这点钱还想打发我...");
                return false;
            }
        }
        public void playMahjong() {
            System.out.println("陪领导人打麻将。。。");
        }
    }
问题:用startActivity()的方式开启的服务,然后new service对象,来调用服务里面的方法,会报下面的异常
10-18 20:31:35.391: E/AndroidRuntime(4870): java.lang.IllegalStateException: Could not execute method of the activity