Android Activity与Service数据交互:Binder、bindService(系列2)

简介: Android Activity与Service数据交互:Binder、bindService(系列2)在实际的开发中,往往通过Android的Service把后台任务完成后,需要将结果传递给上层代码,比如一个Activity启动了Service,当Service在后台完成处理操作后,此时Service需要将结果传递给Activity,该怎么办呢?办法很多,其中一个就是使用和Android Service密切相关的Android Binder。


Android Activity与Service数据交互:Binder、bindService(系列2)

在实际的开发中,往往通过Android的Service把后台任务完成后,需要将结果传递给上层代码,比如一个Activity启动了Service,当Service在后台完成处理操作后,此时Service需要将结果传递给Activity,该怎么办呢?办法很多,其中一个就是使用和Android Service密切相关的Android Binder。
假设一个场景,前台Activity需要做一个计算任务,计算任务很简单,计算两个数值的和a+b=?(在实际开发中,这是不存在的,举这个a+b的场景只是为了举一反三用简单例子说没问题)。我将这个计算过程放到Service里面做,首先需要给Service传递过去a与b的值,然后启动Service的服务计算a+b,接下来Service计算完毕得到结果后,Activity再从Service里面获得计算结果,整个Activity与Service交互至此结束。
但是这个看似简单却在Activity与Service中如果不用bind的模型传递数据将会变得复杂,原因在于当Activity启动Service后,从此Activity与Service天地相隔,不存在太大关系,不能像普通的类一样操作Service及里面的方法体。
下面就用Service的bind解决。
 这篇文章是在上一篇文章《Android Service简介(系列1)》(文章链接:http://blog.csdn.net/zhangphil/article/details/49373939 )的基础上增加bind机制。

大致上Activity与Service通过bind交互的编程模型是:
(第1步)老规矩,还是先继承Service。完成里面的onBind,返回一个自己重写的Binder,在本例中是MyBinder。MyBinder里面一个public get方法返回Service的类实例。
毫无疑问,同时需要在Service里面写好public set/get方法,为后面的Activity访问做好基本set/get操作。
(第2步)在Activity里面bindService。bindService是为了将Activity和Service绑定在一起,大有不求同年同月生,但求同年同月死的味道。
在bindService的时候,需要传递一个ServiceConnection,ServiceConnection像一个桥梁,建立了Activity和Service之间的桥接。事实上也就是为了从ServiceConnection的回调方法onServiceConnected中的获得后台的Service句柄。只要获得Service的句柄,那么什么都好办了。
(第3步)在Activity中拿到Service的句柄后,就可以像操作一个普通的Java类一样传参、取值了。

以上步骤完成后,需要明确一个基本的Activity使用Service的顺序流程,以计算a+b=?为例:
(A)首先需要在Activity里面bindService。bindService时候需要传递过去ServiceConnection,在ServiceConnection的回调方法onServiceConnected中获得Service句柄。
(B)拿到Service句柄后,在Activity中设置Service里面的a与b的值。
(C)startService。startService将跳过onCreate直接进入onStartCommand方法体内,在Service里面的后台操作,也可以简单理解为就是在Service的onStartCommand中的操作。在onStartCommand中计算a+b的和。
(D)上层Activity再次通过之前获得的Service句柄从Service里面get a+b的和。

以上模型和流程的代码实现:
Service类:

package zhangphil.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class MyAppService extends Service {

	private int a = 0, b = 0;
	private int result = 0;

	@Override
	public void onCreate() {
		Log.d(this.getClass().getName(), "onCreate");
	}

	// 需要Service处理的操作在此
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {

		result = a + b;

		Log.d(this.getClass().getName(), "onStartCommand:" + result);

		return super.onStartCommand(intent, flags, startId);
	}

	public int getServiceValue() {
		return result;
	}

	public void setServiceValue(int a, int b) {
		this.a = a;
		this.b = b;
		Log.d(this.getClass().getName(), "setServiceValue:a=" + a + " b=" + b);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return new MyBinder();
	}

	public class MyBinder extends Binder {
		public MyAppService getService() {
			return MyAppService.this;
		}
	}
	
	@Override
	public boolean onUnbind(Intent intent) {
		Log.d(this.getClass().getName(), "onUnbind");
		return super.onUnbind(intent);
	}

	@Override
	public void onDestroy() {
		Log.d(this.getClass().getName(), "onDestroy");
	}
}



测试的Activity MainActivity:

package zhangphil.service;

import java.util.Random;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import zhangphil.service.MyAppService.MyBinder;

public class MainActivity extends Activity {

	private ServiceConnection sc = null;
	private MyAppService myAppService;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Button start = (Button) findViewById(R.id.start);
		start.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				startMyAppService();
			}
		});

		Button bind = (Button) findViewById(R.id.bind);
		bind.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				bindMyAppService();
			}
		});

		Button unbind = (Button) findViewById(R.id.unbind);
		unbind.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				unbindMyAppService();
			}
		});

		Button set = (Button) findViewById(R.id.set);
		set.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Random rand = new Random();
				int a = rand.nextInt(10);
				int b = rand.nextInt(10);
				myAppService.setServiceValue(a, b);
			}
		});

		Button result = (Button) findViewById(R.id.result);
		result.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Toast.makeText(getApplicationContext(), myAppService.getServiceValue() + "", Toast.LENGTH_SHORT).show();
			}
		});

		Button stop = (Button) findViewById(R.id.stop);
		stop.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				stopMyAppService();
			}
		});
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		unbindMyAppService();
		Log.d(this.getClass().getName(), "onDestroy");
	}

	private void startMyAppService() {
		Intent intent = new Intent(this, MyAppService.class);
		this.startService(intent);
	}

	private void bindMyAppService() {
		sc = new ServiceConnection() {

			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				Log.d(this.getClass().getName(), "onServiceConnected");

				MyBinder mBinder = (MyBinder) service;
				myAppService = mBinder.getService();
			}

			@Override
			public void onServiceDisconnected(ComponentName name) {
				Log.d(this.getClass().getName(), "onServiceDisconnected");
			}
		};

		Intent intent = new Intent(this, MyAppService.class);
		this.bindService(intent, sc, Service.BIND_AUTO_CREATE);
	}

	private void stopMyAppService() {
		Intent intent = new Intent(this, MyAppService.class);
		boolean bool = this.stopService(intent);
	}

	private void unbindMyAppService() {
		if (sc != null)
			this.unbindService(sc);
	}
}


注意记到!在Activity退出时候,请unbindService,或者stopService。

相关文章
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
1659 4
|
Java Linux Android开发
移动应用开发与操作系统的交互:深入理解Android和iOS
在数字时代,移动应用成为我们日常生活的一部分。本文将深入探讨移动应用开发的核心概念、移动操作系统的工作原理以及它们如何相互作用。我们将通过实际代码示例,展示如何在Android和iOS平台上创建一个简单的“Hello World”应用,并解释其背后的技术原理。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和知识。
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
709 11
|
开发工具 Android开发 开发者
Android平台如何不推RTMP|不发布RTSP流|不实时录像|不回传GB28181数据时实时快照?
本文介绍了一种在Android平台上实现实时截图快照的方法,尤其适用于无需依赖系统接口的情况,如在RTMP推送、RTSP服务或GB28181设备接入等场景下进行截图。通过底层模块(libSmartPublisher.so)实现了截图功能,封装了`SnapShotImpl.java`类来管理截图流程。此外,提供了关键代码片段展示初始化SDK实例、执行截图、以及在Activity销毁时释放资源的过程。此方案还考虑到了快照数据的灵活处理需求,符合GB/T28181-2022的技术规范。对于寻求更灵活快照机制的开发者来说,这是一个值得参考的设计思路。
479 1
|
存储 XML Java
Android 文件数据储存之内部储存 + 外部储存
简介:本文详细介绍了Android内部存储与外部存储的使用方法及核心原理。内部存储位于手机内存中,默认私有,适合存储SharedPreferences、SQLite数据库等重要数据,应用卸载后数据会被清除。外部存储包括公共文件和私有文件,支持SD卡或内部不可移除存储,需申请权限访问。文章通过代码示例展示了如何保存、读取、追加、删除文件以及将图片保存到系统相册的操作,帮助开发者理解存储机制并实现相关功能。
3065 2
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
1037 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
XML Android开发 UED
"掌握安卓开发新境界:深度解析AndroidManifest.xml中的Intent-filter配置,让你的App轻松响应scheme_url,开启无限交互可能!"
【8月更文挑战第2天】在安卓开发中,scheme_url 通过在`AndroidManifest.xml`中配置`Intent-filter`,使应用能响应特定URL启动或执行操作。基本配置下,应用可通过定义特定URL模式的`Intent-filter`响应相应链接。
576 12
|
缓存 API Android开发
Android经典实战之Kotlin Flow中的3个数据相关的操作符:debounce、buffer和conflate
本文介绍了Kotlin中`Flow`的`debounce`、`buffer`及`conflate`三个操作符。`debounce`过滤快速连续数据,仅保留指定时间内的最后一个;`buffer`引入缓存减轻背压;`conflate`仅保留最新数据。通过示例展示了如何在搜索输入和数据流处理中应用这些操作符以提高程序效率和用户体验。
479 6
|
编解码 网络协议 前端开发
如何实现Android平台GB28181设备接入模块按需打开摄像头并回传数据
后台采集摄像头,如果想再进一步扩展,可以把android平台gb28181的camera2 demo,都移植过来,实现功能更强大的国标设备侧,这里主要是展示,收到国标平台侧的回传请求后,才打开摄像头,才开始编码打包,最大限度的减少资源的占用
483 3

热门文章

最新文章