onBind,onRebind,onUnbind

最近给app添加计步的功能,开一个service,然后用ipc进程间通信,重新复习了一下android四大组件之一的service;

先来看service的生命周期:

service的生命周期,从它被创建开始,到它被销毁,可以有两条不同的路径:
A started service
被开启的service通过其他组件调用startService()被创建
这种service可以无限地运行下去,必须调用stopSelf()方法或者其他组件调用stopService()方法来停止它.
当service被停止时,系统会销毁它。

A bound service
被绑定的service是当其他组件调用bindService()来创建的。
客户可以通过IBinder接口和service进行通信。
客户可以通过unbindService()方法来关闭连接。
一个service可以同时和多个客户绑定,当多个客户都解除绑定后,系统会销毁service。

当然,可以同时调用startService和bindService开启和绑定service

下面这张图分别是startService和bindService生命周期的回调函数,可以实现它们来监听service的状态变化,并在适当的时候执行适当的工作

onCreate()
不管你是开启还是绑定服务,最开始的回调函数肯定是onCreate(),并且该回调只会执行一次,之后再执行开启或绑定服务都不会走该回调函数,除非你的service被销毁了。

onStartCommond()
每次执行startService()都会调用一次onStartCommond()。

onDestory()
service被销毁时,回调该函数

我觉得重要的还是bindService()那几个回调函数onBind(),onUnbind(),onRebind()。

看个栗子,估计大家就明白了:
一般我们在启动service都会同时调用startService和bindService,
startService之后,如果没有调用stopStervice,服务会一直在后台,除非被系统杀死,bindService是将组件和服务绑定起来,可以通过unBindService来解绑。首先在activity中我们调用了startService和bindService()后,会回调onBind()方法,

    @Override
    public IBinder onBind(Intent intent) {
        Log.e("bindService", "onBind");
        return mBinder;
    }

在activity的onDestory()方法里我们调用

    @Override
    public void onDestroy() {
        super.onDestroy();
            if (isBind) { //如果绑定了
            unbindService(conn); //解绑
        }
    }

onUnbind回调

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("bindService", "onUnbind");
        return super.onUnbind(intent);
    }

这时候将activity销毁后,打印出的日志如下
可以看到,先绑定了,之后activity销毁后,又解绑了。

然后我再打开该activity,再次执行bindService,onBind()方法并不会执行,因为我们的service通过startService已经在后台开启了,这时候再次bindServce是不会调用onBind()方法的,除非你把服务都杀掉后,才后重新走onBind方法,服务一直在后台,对应的onBind只会走一次,那么之后如果调用bindService()之后,其实走的都是onRebind()方法,当然前提是在onUnbind()的返回一定要为true
如下:

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("bindService", "onUnbind");
        return true;
    }

改完之后,


可以看到,只要service没没被杀死,不管你进来几次,都是回调onRebind和onUnbind方法,并且如果你只是bindService,并没有stopService也是一样的。

下图展示了service(被开启,还允许绑定)的生命周期

因为自己正好用到了service,所以对service的生命周期又重新学习了一遍,当你对service的生命周期走向不了解的时候,建议你每一个回调方法里面都打日志,这样就很清楚了。
当时我遇到的问题是,在app打开时,点开service的前台notification,跳转到相应的计步页面,在app关闭时,点开service的前台notification,先启动app,在跳转到相应的计步页面,这个时候,其实只要在service的这几个生命周期里面加一个全局变量,判断当前app是否启动,然后在notification中进行判断就好了,回调了onUnBind,则说明app关闭了,可以在回调onUnbind的时候设置一个变量记录如isBind = false,回调了onBind或者onRebind说明app重启了,可以记录为isBind = true,这样在notification中就可以通过isBind的值来启动app还是直接跳转相应界面了。

虽然很早就了解生命周期,还是在实际运用中才能加深印象,并巩固。

发布了40 篇原创文章 · 获赞 5 · 访问量 2万+
展开阅读全文

通过Handler实现Service和Activity的数据交互,与onbind返回Binder对象冲突,我该如何解决?

07-10

在做service和activity通讯,需要服务能够控制活动的运行,同时能够实时进行数据传输 我通过Handler实现Service和Activity的数据交互,但尴尬的是onBind已经用于传递BleBind的一个实例了,没办法return messenger.getBinder(); ``` package com.example.bluserver; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.util.Log; import android.widget.TextView; import android.widget.Toast; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; public class bluService extends Service { public static final int MSG = 123; private static final String TAG = "BleService"; private BluetoothAdapter mBA; private Context mContext; private final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");//这是蓝牙透传的uuid // 这里本身即是服务端也是客户端,需要如下类 private BluetoothSocket mSocket; private BluetoothDevice mOldDevice; private BluetoothDevice mCurDevice; // 输出流_客户端需要往服务端输出 private OutputStream os; private Messenger mActivityMessenger; private BleBinder bleBinder=new BleBinder(); @Override public IBinder onBind(Intent intent) { Messenger messenger=new Messenger(handler); //return messenger.getBinder();//Handler实现Service和Activity的数据交互 return bleBinder;//返回BleBinder实例供活动调用 } class BleBinder extends Binder{//以下是以供调用的公共方法 //开始读取传感器数据 public void startread(){ { new Thread(new Runnable() { @Override public void run() { try { Log.d(TAG,"开始运行run()函数"); InputStream is = mSocket.getInputStream(); Log.d(TAG,"已获取输入流"); while (true) { synchronized (this) { //Log.d(TAG,"已获取锁"); //Thread.sleep(50); byte[] tt = new byte[is.available()]; if (tt.length > 0) { is.read(tt, 0, tt.length); Message msg = new Message(); msg.obj = new String(tt, "GBK"); //大概在这里要获取整个字符串,字符串以回车分割,如此才能准确识别 Log.e(TAG, "客户端:" + msg.obj); showToast("客户端:" + msg.obj); mActivityMessenger.send(msg); //handler.sendMessage(msg); } } } } catch (Exception e) { e.printStackTrace(); } } }).start(); } } public void stopread(){}//停止读取传感器数据 /** * 弹出Toast窗口 * * @param message */ private void showToast(String message) { if (mContext != null) { Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); } else { Log.e(TAG, "message:" + message); } } /** * 主动连接蓝牙 * * @param device */ public void connectDevice(BluetoothDevice device) { // 判断是否在搜索,如果在搜索,就取消搜索 if (mBA.isDiscovering()) { mBA.cancelDiscovery(); } try { // 获得远程设备 Log.e(TAG, "开始检索"); if (mCurDevice == null || mCurDevice != mOldDevice) { mCurDevice = mBA.getRemoteDevice(device.getAddress()); Log.e(TAG, device.getAddress()); mOldDevice = mCurDevice; Log.e(TAG, "device:" + mCurDevice); mSocket = mCurDevice.createRfcommSocketToServiceRecord(MY_UUID); // 连接 mSocket.connect(); // 获得输出流 os = mSocket.getOutputStream(); Log.e(TAG, "获取输入流"); startread(); Log.e(TAG, "开启读线程"); //intent流转byte数组 // byte[] input=ByteToInputStream.input2byte(mSocket.getInputStream()); // Intent intent=new Intent(); // intent.putExtra("inputstream",input); // mContext.startActivity(intent); } // 如果成功获得输出流 Log.e(TAG, "3"); } catch (IOException e) { e.printStackTrace(); } } /** * 判断是否打开蓝牙 * * @return */ public boolean isEnabled() { if (mBA.isEnabled()) { return true; } return false; } /** * 传输数据 * * @param message */ public void write(String message) { try { if (os != null) { os.write(message.getBytes("GBK")); } Log.e(TAG, "write:" + message); } catch (IOException e) { e.printStackTrace(); } } public BluetoothDevice getCurDevice() { return mCurDevice; } } public bluService() { mBA = BluetoothAdapter.getDefaultAdapter(); } private Handler handler = new Handler() { public void handleMessage(Message msg) { //Toast.makeText(this,String.valueOf(msg.obj),Toast.LENGTH_LONG); //将在此处向主线程发送信息,用于更新界面(已废弃) //将在此处处理来自活动的消息,发送消息在线程内 // 参考代码 https://blog.csdn.net/CodeNoodles/article/details/51679532 switch (msg.what){ case MSG: mActivityMessenger = msg.replyTo; break; } Log.e(TAG, "服务端:" + msg.obj); super.handleMessage(msg); } }; @Override public void onDestroy() { Log.d(TAG,"服务已销毁"); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG,"服务已启动"); return super.onStartCommand(intent, flags, startId); } @Override public void onCreate() { super.onCreate(); Log.d(TAG,"服务已创建"); } } ``` 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览