Service与Activity通信 回调方式***

要实现service与activity的高强度通信用什么方法?

service与activity之前的通信方式有很多,回调接口方式、观察者模式、广播、还有handler等,方法有很多,但要高强度地通信,个人觉得还是用回调接口的方式比较妥当(虽然本人开始也是用的传入的handler。。。哈哈,用handler的话,如果涉及到service要向多个activity传送数据就变得麻烦了)。所以在这里记录下回调接口的方式进行通信:

1、怎样在启动一个Service时向它传递数据

关键点:Intent传值,onStartCommand()接收。

2、怎样向运行的Service中同步数据

关键点:通过onBind()获取Service实例,然后再调用Binder中的相关方法。

3、怎样侦听Service中数据变化

关键点:通过回调函数达到目的。

一、准备Service

先贴出Service的详细代码,然后再慢慢分析

undefined

import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.Binder;
public class MyService extends Service {
    private String data = "默认消息";
    private boolean serviceRunning = false;

    // 必须实现的方法,用于返回Binder对象
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("--onBind()--");
        return new MyBinder();
    }

    public class MyBinder extends Binder {
        MyService getService() {
            return MyService.this;
        }

        public void setData(String data) {
            MyService.this.data = data;
        }
    }

    // 创建Service时调用该方法,只调用一次
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("--onCreate()--");
        serviceRunning = true;
        new Thread() {
            @Override
            public void run() {
                int n = 0;
                while (serviceRunning) {
                    n++;
                    String str = n + data;
                    System.out.println(str);
                    if (dataCallback != null) {
                        dataCallback.dataChanged(str);
                    }
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
        }.start();
    }

    // 每次启动Servcie时都会调用该方法
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("--onStartCommand()--");
        data = intent.getStringExtra("data");
        return super.onStartCommand(intent, flags, startId);
    }

    // 解绑Servcie调用该方法
    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("--onUnbind()--");
        return super.onUnbind(intent);
    }

    // 退出或者销毁时调用该方法
    @Override
    public void onDestroy() {
        serviceRunning = false;
        System.out.println("--onDestroy()--");
        super.onDestroy();
    }

    DataCallback dataCallback = null;

    public DataCallback getDataCallback() {
        return dataCallback;
    }

    public void setDataCallback(DataCallback dataCallback) {//注意这里以单个回调为例  如果是向多个activity传送数据 可以定义一个回调集合 在此处进行集合的添加
        this.dataCallback = dataCallback;
    }

    // 通过回调机制,将Service内部的变化传递到外部
    public interface DataCallback {
        void dataChanged(String str);
    }

}

代码分析:我们都知道,通过startService启动一个Service时,Service会调用生命周期函数onStartCommand(),在代码中创建一个Service,在onStartCommand()方法中获取从Activity传递过来的数据,并在Service的onCreate()方法中开启一个新的线程,使其循环调用回调函数,以达到通知外界信息改变的目的。并在Service中通过Binder类,将Service与Activity链接起来,以实现信息同步。

二、准备布局文件

布局文件比较简单,直接贴出,就不分析了,activity_main.xml如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_out"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="显示区域" />

    <EditText
        android:id="@+id/et_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10" >

        <requestFocus />
    EditText>

    <Button
        android:id="@+id/btn_start_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="startService" />

    <Button
        android:id="@+id/btn_stop_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="stopService" />

    <Button
        android:id="@+id/btn_bind_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="bindService" />

    <Button
        android:id="@+id/btn_unbind_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="unbindService" />

    <Button
        android:id="@+id/btn_sync_data"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="同步数据" />

LinearLayout>

三、准备Activity

MainActivity代码如下:

public class MainActivity extends Activity implements OnClickListener {

    private Intent intent = null;
    private Button btn_start_service;
    private Button btn_stop_service;
    private Button btn_bind_service;
    private Button btn_unbind_service;
    private Button btn_sync_data;
    private EditText et_data;
    private TextView tv_out;
    MyServiceConn myServiceConn;
    MyService.MyBinder binder = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intent = new Intent(this, MyService.class);
        myServiceConn = new MyServiceConn();
        setOnClick();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_start_service:
            //用intent启动Service并传值
            intent.putExtra("data", et_data.getText().toString());
            startService(intent);
            break;
        case R.id.btn_stop_service:
            //停止Service
            stopService(intent);
            break;
        case R.id.btn_bind_service:
            //绑定Service
            bindService(intent, myServiceConn, Context.BIND_AUTO_CREATE);
            break;
        case R.id.btn_unbind_service:
            //解绑Service
            if (binder != null) {
                unbindService(myServiceConn);
            }
            break;
        case R.id.btn_sync_data:
            //注意:需要先绑定,才能同步数据
            if (binder != null) {
                binder.setData(et_data.getText().toString());
            }
            break;
        default:
            break;
        }
    }

    class MyServiceConn implements ServiceConnection {
        // 服务被绑定成功之后执行
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // IBinder service为onBind方法返回的Service实例
            binder = (MyService.MyBinder) service;
            binder.getService().setDataCallback(new MyService.DataCallback() {
                //执行回调函数
                @Override
                public void dataChanged(String str) {
                    Message msg = new Message();
                    Bundle bundle = new Bundle();
                    bundle.putString("str", str);
                    msg.setData(bundle);
                    //发送通知
                    handler.sendMessage(msg);
                }
            });
        }

        @SuppressLint("HandlerLeak")
        Handler handler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                //在handler中更新UI
                tv_out.setText(msg.getData().getString("str"));
            };
        };

        // 服务奔溃或者被杀掉执行
        @Override
        public void onServiceDisconnected(ComponentName name) {
            binder = null;
        }
    }

    private void loadUI() {
        btn_start_service = (Button) findViewById(R.id.btn_start_service);
        btn_stop_service = (Button) findViewById(R.id.btn_stop_service);
        btn_bind_service = (Button) findViewById(R.id.btn_bind_service);
        btn_unbind_service = (Button) findViewById(R.id.btn_unbind_service);
        btn_sync_data = (Button) findViewById(R.id.btn_sync_data);
        et_data = (EditText) findViewById(R.id.et_data);
        tv_out = (TextView) findViewById(R.id.tv_out);
    }

    private void setOnClick() {
        loadUI();
        btn_start_service.setOnClickListener(this);
        btn_stop_service.setOnClickListener(this);
        btn_bind_service.setOnClickListener(this);
        btn_unbind_service.setOnClickListener(this);
        btn_sync_data.setOnClickListener(this);
    }

}

代码分析:

1、加载UI,初始化变量啥的跳过了,主要说一下关键代码,在第28代码中,与启动一个Activity类似,通过Intent想要启动的Service传递参数。

2、在37行通过bindService绑定Service,然后在ServiceConnection中获取Service类中onBind方法返回的实例,获取实例Service实例后,我们就可以通过调用Service中MyBinder的setData()方法对Service进行同步数据,如48行所示。

3、整个过程,在Service的onCreate方法中都会循环调用回调函数,同时我们在MainActivity中重写回调方法以实现更新UI。

四、测试

1、启动示例后,在输入框输入你好,然后点击startService,界面和对应的日志如下:

Service与Activity通信 回调方式***

看了下面的代码后就会知道,此时因为没有绑定service,所以办法执行回调函数更新UI,所以显示区域没有更新。

2、点击bindService后,界面如下:

Service与Activity通信 回调方式***

当执行bindService后,在ServiceConnection方法中就会执行执行回调函数更新UI,此时显示区域开始更新。

3、改变输入框内容,点击同步数据,界面和对应的日志如下:

Service与Activity通信 回调方式***

Original: https://www.cnblogs.com/jiangzhaowei/p/11341890.html
Author: 江召伟
Title: Service与Activity通信 回调方式***

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/552168/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球