急求一个重口味网站跑步app的android源代码,记录跑步信息,测算能耗,发布一些健康小知识,不需要太好,能用就可以。

轻+计步相关实现
现在人们越来越注重健康,相应的健康类app也是种类繁多,使用的最多的就是减肥健身类和计步跑步类的应用。而现在安卓上的计步无非就是利用手机自带的传感器,获取实时返回的数据后,再利用各自的算法过滤掉无效的步数,通过应用开启的服务保持后台持续进行,监测一整天的步行。
但因为市面上的安卓手机千差万别,不同的厂商定制出来的系统又是不同的,所以传感器的处理也是有所差别的,我们通过长时间收集用户反馈不断进行优化,本文将针对我们应用自带的计步功能实现和遇到的困难和解决方法一一详解,希望对读者有所帮助,也欢迎读者指出缺点互相改进。
2.1计步service
1、进到计步页的时候,我们需要启动一个service来保持后台计步,所以首先定义一个自定义的Service。(一开始设计的时候没有考虑到后台进程这些问题,所以启动service的方法是放在计步页的,后来证实不可取,后面的相关问题会谈到这个问题)
class StepService extends Service{}
开始计步服务
private void startStepService() {
Intent intent = new Intent(PedometerActivity.this, StepService.class);
Bundle bundle = new Bundle();
//intent带参数需要Bundle
bundle.putInt("op", 1);
intent.putExtras(bundle);
startService(intent);
上面启动service传递的参数是为了控制开始暂停的,下面会讲到。
2、绑定service,为了能够在计步页实时显示计步服务中拿回的步数,我们还需要在计步页绑定一下service,只需要在计步页绑定,退出计步页时解除绑定。
* 这里绑定是为了计步页面实时显示service传回的步数
private void bindStepService() {
bindService(new Intent(PedometerActivity.this, StepService.class), mConnection,
Context.BIND_AUTO_CREATE);
private StepService mS
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = ((StepService.StepBinder) service).getService();
mService.registerCallback(mCallback);
mService.reloadSettings();
public void onServiceDisconnected(ComponentName className) {
mService =
以下是service的回调
private StepService.ICallback mCallback = new StepService.ICallback() {
public void stepsChanged(int value) {
mHandler.sendMessage(mHandler.obtainMessage(STEPS_MSG, value, 0));
public void paceChanged(int value) {
mHandler.sendMessage(mHandler.obtainMessage(PACE_MSG, value, 0));
public void distanceChanged(float value) {
mHandler.sendMessage(mHandler.obtainMessage(DISTANCE_MSG, (int) (value * 1000), 0));
public void speedChanged(float value) {
mHandler.sendMessage(mHandler.obtainMessage(SPEED_MSG, (int) (value * 1000), 0));
public void caloriesChanged(float value) {
mHandler.sendMessage(mHandler.obtainMessage(CALORIES_MSG, (int) (value), 0));
public void timeChanged(String value) {
Message msg = new Message();
msg.what = TIME_MSG;
mHandler.sendMessage(msg);
2.2service中相关监听
3、在计步service的onCreate()方法中初始化步数监听。
首先定义一个获取步数的接口:
public interface StepListener {
void onStep();
void passValue();
然后需要定义一些计步相关的监听类
StepDisplayermStepD//步数
DistanceNotifiermDistanceN//距离
SpeedNotifiermSpeedN//速度
CaloriesNotifiermCaloriesN//热量
以获取步数的监听类为例:
/** 将计算的步数传递给activity显示 */
public class StepDisplayer implements StepListener{
public static int mCount = 0;
public StepDisplayer(PedometerSettings settings){
notifyListener();
public void setSteps(int steps){
notifyListener();
public void onStep() {
mCount ++;
notifyListener();
public void passValue() {
public void reloadSettings(){
notifyListener();
public interface Listener{
void stepsChanged(int value);
void passValue();
private ArrayList mListeners = new ArrayList();
public void addListener(Listener l){
mListeners.add(l);
public void notifyListener(){
for(Listener listener:mListeners){
listener.stepsChanged(mCount);
然后需要设置相关的监听:
mStepDisplayer.addListener(mStepListener);
mStepDetector.addStepListener(mStepDisplayer);
(mStepDetector为StepDetector声明的对象,StepDetector类实现SensorEventListener接口)
所以直接在步数通知的回调中,可以显示处理拿回步数。
private StepDisplayer.Listener mStepListener = new StepDisplayer.Listener() {
public void stepsChanged(int value) {
//此处拿到每次的步数,做相应的处理
2.3传感器的处理
说到这里,只是讲到了在service中设置相关的通知,方便实时拿回步数,但还没讲到传感器的处理,所以下面是介绍传感器获取步数的操作。
2.3.1onStart()的不同处理
上面讲到的启动服务传递的参数,是为了控制开始和暂停计步的,其实就是控制传感器的注册和取消注册,启动服务的方法可以多次调用,在service的onStart()里接收不同的参数进行不同的处理。
public void onStart(Intent intent, int startId) {
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
int op = bundle.getInt("op");
switch(op){
case 1: //开始
registerDetector();
case 2: //暂停
unregisterDetector();
mNM.cancel(R.string.app_name);
2.3.2定义传感器相关类
SensorEventListener类是手机传感器的监听类,SensorManager类为传感器管理类;
2.3.3注册传感器
mSensor = mSensorManager.getDefaultSensor(sensorType);
mSensorManager.registerListener(mStepDetector,
SensorManager.SENSOR_DELAY_NORMAL);
这里的mSensor为Sensor类。上面第三个参数为采样率:最快、游戏、普通、用户界面。当应用程序请求特定的采样率时,其实只是对传感器子系统的一个建议,不保证特定的采样率可用。
最快:SensorManager.SENSOR_DELAY_FASTEST
最低延迟,一般不是特别敏感的处理不推荐使用,该种模式可能造成手机电力大量消耗,由于传递的为原始数据,算法不处理好将会影响游戏逻辑和UI的性能。
游戏:SensorManager.SENSOR_DELAY_GAME
游戏延迟,一般绝大多数的实时性较高的游戏都使用该级别。
普通:SensorManager.SENSOR_DELAY_NORMAL
标准延迟,对于一般的益智类或EASY级别的游戏可以使用,但过低的采样率可能对一些赛车类游戏有跳帧现象。
用户界面:SensorManager.SENSOR_DELAY_UI
一般对于屏幕方向自动旋转使用,相对节省电能和逻辑处理,一般游戏开发中我们不使用。
2.3.4两种传感器处理
现在使用到的两种模式,用户可以在计步设置页手动选择,分别为普通模式和内置计步器模式。普通模式为采用加速度传感器,需要算法过滤掉无效的步数;内置计步器则不需要现在大部分手机(4.4以上)自带计步传感器,可以直接在回调里拿回步数直接显示,不需要考虑步数是不是有效的,传感器本身已经帮你处理了。
Sensor.TYPE_ACCELEROMETER;//默认采用加速度传感器来处理,需要算法过滤无效步数
Sensor.TYPE_STEP_DETECTOR;//采用手机4.4以上自带计步处理器,不需要算法过滤无效步数
所以需要判断手机是不是自带内置计步器,相关代码如下:
* 判断手机是否支持4.4以上自带计步处理器
public void judgeIsSupportStepDetector() {
int sensorTypeC = Sensor.TYPE_STEP_COUNTER;
PackageManager pm = getPackageManager();
boolean flag = pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR);
if (flag) {
SensorManager mSensorManager = (SensorManager) this
.getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(sensorTypeC) != null) {
//支持内置计步器
2.3.5传感器的回调
SensorEventListener的onSensorChange()方法里,根据注册传感器时的类型,分别判断是哪种传感器回调的数据。
onSensorChanged(SensorEventevent)方法里通过SensorEvent获取类型和相关参数:
如果event.sensor.getType()==Sensor.TYPE_STEP_DETECTOR则表示设置了内置计步器模式,判断event.values[0]==1.0的话,调用我们前面定义的接口stepListener.onStep()本地步数直接加1;
如果event.sensor.getType()==Sensor.TYPE_ACCELEROMETER,表示采用加速度传感器,我们就不能像内置计步器那样直接本地步数加1,而是要通过自己的算法来过滤无效的步数。下面会介绍下过滤的算法的实现原理。
2.3.6计步过滤算法实现原理(只是过滤传感器无效的振幅)
(只针对普通模式,也就是加速度传感器)
普通模式下,传感器会不断传回不同的值,这个时候我们需要设置相关条件去过滤掉这些无效的振幅,得出我们最后需要的值,也就是有效的那一步。
(1)第一个条件:时间间隔不能太短。
定义一个最后的有效步数的时间a,默认是0毫秒,需满足最后(1)(2)(3)所有条件得出一个有效步数后才把当前时间赋给a,在每次传感器回调中获取当前时间b,第一个判断成立的条件是a-b>90,即两次振幅的间隔必须大于90毫秒。
因为设置了灵敏度调节,所以这个时间90是可设置的,设置越小则灵敏度越高。
(2)第二个条件:振幅速度不能太小。
计算当前振幅速度speed:
longdiff=now-mLastT(now为当前时间,mLastTime为条件1的a)
floatspeed=Math.abs(event.values[SensorManager.DATA_X] +event.values[SensorManager.DATA_Y]+event.values[SensorManager.DATA_Z]-mLastX-mLastY-mLastZ)/diff*10000;
mLastX,mLastY,mLastZ分别为x轴,y轴,z轴的值。
以下赋值只需要在第一个判断成立时:
mLastTime=
mLastX=event.values[SensorManager.DATA_X];
mLastY=event.values[SensorManager.DATA_Y];
mLastZ=event.values[SensorManager.DATA_Z];
默认速度speed大于60为条件2成立,因为设置了灵敏度调节,所以这个60是变化的,设置越小则灵敏度越高。
(补充一点,介绍android的坐标系是如何定义x,y,z轴的。
x轴的方向是沿着屏幕的水平方向从左向右,如果手机不是正方形的话,较短的边需要水平放置,较长的边需要垂直放置。
Y轴的方向是从屏幕的左下角开始沿着屏幕的的垂直方向指向屏幕的顶端。
将手机放在桌子上,z轴的方向是从手机指向天空。)
(3)第三个条件:
同时满足((++mShakeCount>=8)且(now-mLastShake>520),
这里mShakeCount为有效震动次数,必须大于8才开始计算步数,什么情况下归零呢?
在条件一前面加多一个处理,
if((now-mLastForce)>2000){
mShakeCount=0;
这里的mLastForce为条件二成立时赋予当前时间,如果两次震动间隔大于2000毫秒,则上面的mShakeCount归零。
mLastShake为上一次获取到有效步数时记录的时间,两次震动的最小时间间隔低于520毫秒则不算有效步伐。
根据上述三个条件同时依次成立,得出来的视为有效步数。
(请参考源代码)
到这里,大概计步的实现流程就结束了。但实际情况下,遇到的问题却是千奇百怪,单单是写这样的流程是无法满足我们的计步应用在后台长时间运行的。所以我们总结了用户的反馈后,整理出了以下的问题和相应的解决方法。
3,遇到的问题及相应的解决办法
1、计步不准。
在以前的版本中,我们只是利用速度传感器去处理计步,而忽略了不同手机厂商速度传感器的敏感度时不同的,所以导致在相同的过滤算法下,不同手机计步会有很大偏差。
解决方法:
(1)增加调节灵敏度调节入口,只针对速度传感器类型的,通过设置速度和两次有效步数时间间隔来提高或降低敏感度。
(2)安卓4.4新增了一个新的传感器类型Sensor.TYPE_STEP_DETECTOR计步传感器,经测试发现注册这个类型的传感器,步数最为准确。后来发现不只是4.4的系统,4.4以上的也支持,但不是都支持。
(3)增加普通模式和内置计步器模式,分别为速度传感器和计步传感器模式供用户自主选择。
2、锁屏不计步。
遇到过很多用户反馈锁屏后计步完全停滞了,检查发现并不是计步的服务停止了,而是传感器根本没响应,但屏幕亮了之后又能正常计步。有些手机厂商为了省电,会在锁屏下把一些传感器关闭或者敏感度降的极低。当然这是一两年前发现的问题,现在大部分手机应该不会有这个问题。
解决方法:
增加强制计步模式。也就是监听用户锁屏后,强制唤醒屏幕,但是屏幕亮度为最低,保证唤醒传感器的同时,不至于太耗电。这里不赘述强制唤醒屏幕的方法。
3、计步了一段时间后不计步了,要进入计步页才能恢复。
我们原来只是在计步页开启和绑定计步服务,而且并没有判断计步服务是否正常,所以导致应用的进程因为各种情况结束掉后,必须进入计步页才能恢复。
解决方法:
(1)判断计步服务是否正常运行
代码如下:
* 判断某个服务是否正在运行的方法
* @param mContext
* @param setpPakcageName 是包名+服务的类名(例net.loonggg.testbackstage.TestService)
* @return true代表正在运行,false代表服务没有正在运行
public static boolean isStepServiceWork(Context mContext) {
boolean isWork =
ActivityManager myAM = (ActivityManager) mContext
.getSystemService(Context.ACTIVITY_SERVICE);
List myList = myAM.getRunningServices(40);
if (myList.size() <= 0) {
for (int i = 0; i < myList.size(); i++) {
String mName = myList.get(i).service.getClassName().toString();
if (mName.equals(setpPakcageName)) {
return isW
(2)父类MainActivity类的onResume()判断计步服务是否正常,如果已经关闭了则重新启动服务,不需要进入计步页才启动;
(3)推送消息的监听里判断计步服务,同上;
(4)增加锁屏和解锁屏幕的广播,在广播里判断计步服务是否正常;
(5)点击手机硬件menu键或home键,弹出正在运行的应用列表,找到我们的应用,下拉后松开,锁住应用,就能防止应用进程被系统杀掉。(最可靠)
4、计步过于灵敏,不走动摇晃手机都会计步。
使用过乐动力或动动的都会发现,你刚开始走步的时候它不会立马更新步数,等走了大概10步后才会开始更新,如果走了几步又停下来一定时间之后,发现又得重新走大概10步才会更新步数。
解决方法:
新增一个稳定步数范围的算法,原理如下:
(1)定义一个有效步数累计的对象startUsefulStep
(2)每获取一个有效步数时记录下时间,两步间隔大于于5秒的话,重新开始过滤有效步数;
(3)每步间隔小于5秒,startUsefulStep累加,连续走了10步;
* 是否开始有效步数的计步
public static boolean isStartUsefulStep(int step) {
boolean isStartPed =//是否正式开始计步
SharedPreferences mSetting =
PedometerSettings mPedometerSettings =
if (mSetting == null || mPedometerSettings == null) {
mSetting =
PreferenceManager.getDefaultSharedPreferences(ApplicationEx.getInstance());
mPedometerSettings = new PedometerSettings(mSetting, ApplicationEx.getInstance());
startUsefulStep +=
//两步的间隔大于5秒,重新开始过滤无效步数
if ((new Date().getTime() - mPedometerSettings.getLastPedTime()) > 5000) {
startUsefulStep = 0;
mPedometerSettings.saveLastPedTime(new Date().getTime());
//每步间隔为5秒内,连续走了10步,视为正式开始计步
if (startUsefulStep >= 10) {
isStartPed =
return isStartP
这样的话,当执行完这个方法后结果为true时,要先在原步数上加10步再开始累加。
5、应用因为崩溃或其他原因导致程序退出,下次进来时步数不见了
这种情况很好处理,在计步的回调方法里,判断当前的步数的倍数是不是9的倍数(这个数字自己定义,但是不能太大,最好不要超过50;也不要每一步就保存;最好也不要使用10的倍数,不然看起来每次恢复的步数都是10的倍数,会有点假。),是的话保存一次步数到文件,下次进来的时候判断一下文件里保存的步数。
4,未能解决的问题
1、进程被系统干掉。例如oppo,自带的安全中心-省电管理中,如果未将应用加入到可信赖的列表或者是关闭省电模式,锁屏后应用进程容易被杀掉;我们告知用户的操作方法是点击硬件menu键或home键,弹出正在运行的应用列表,找到我们的应用,下拉一次后松开锁住应用,就能防止应用进程被杀掉。
2、计步算法不够准确,不同手机上的结果还是有较大偏差;
3、当前的算法不支持智能识别跑步
计步本身其实没什么太多的技术难点,复杂的是过滤有效振幅的算法(当前我们的算法还是比较弱智的水平),能够较智能(我不认为现在计步比较好的像乐动力,动动的算法就是百分百智能的)识别不同的场景。而且不同手机的传感器硬件也是不同的,所以可能相同的算法处理出来的逻辑又会有所不同。所以这个还需要不断的优化,但也从中更加认识安卓平台碎片化的严重性,也能更好的知道如何应对同设备带来的不同问题,从中也能了解到不同用户的使用习惯,更好的改进计步的功能。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'概述 WebCL是Khronos组织定义的一组Javascript接口,通过binding的方式将OpenCL异构并行计算的能力引入Web领域。WebCL使得Web应用可以使用GPU以及多核CPU的并行处理能力以实现显著的性能提升。WebCL于2014年由Khronos组织发布,目前版本基于OpenCL 1.1. 注意:WebCL并不能一定让Web应用获得性能提升。根据阿姆达尔定律,使用并行技术提升程序性能所能达到的加速比上限值是由程序的不可并行部分所占比例决定的。若程序逻辑本身不可并行部分所占比例较多,则使用并行技术提升程序性能所达到的效果也是有限的。 Crosswalk 14开始支持并默认启用WebCL技术。需要注意的是,目前WebCL特性需要在设备预装了OpenCL运行环境的情况下才能正常工作。一些OEM在他们的产品中预装了OpenCL的运行环境,一般这些动态库都会被命名为libOpenCL.so, libOpenCL.so.1 或者 libPVROCL.so,并被存放在/system/lib或者/system/vendor/lib. 如果你无法找到上述的动态库,那么很抱歉WebCL无法在你的设备上工作,或者你可以通过人工安装OpenCL 运行环境的方法使WebCL发挥作用。在这篇教程中,我们将编写一个简单但是典型的WebCL程序。该程序用来计算多达1,000,000个数字的平方根。Javascript传统的实现方式如下所示:varlen = 1000000;vararr1 = new Float32Array(len);vararr2 = new Float32Array(len);for(i = 0; i & i++) arr1[i]=for(i = 0; i & i++) arr2[i]= Math.sqrt(arr1[i]);WebCL程序实际上由两部分组成,第一部分叫做kernel,该部分以类C99的语法编写。Kernel是运行在GPU或者其它支持OpenCL设备上的代码段。另一部分是Javascript的主机端代码,该部分由Javascript编写完成。主机端代码通过使用WebCL标准中定义的API控制kernel代码的执行。 将上述Javascript代码段表达的逻辑用WebCL实现,我们需要完成以下步骤:·
创建WebCL上下文。·
在WebCL设备上分配存储空间供程序使用。该存储空间用来保存输入输出
创建WebCL程序对象。该程序对象包含在WebCL设备上执行的代码。·
通过创建命令队列并向队列中加入一系列的命令来执行计算。
创建WebCL上下文 WebCL上下文是一系列与WebCL运行环境相关的对象的集合。它决定了我们将要使用的WebCL设备的类型。同时WebCL上下文管理其他WebCL对象,例如内存对象,命令队列和WebCL程序对象。以下代码展示了如何为GPU设备创建WebCL上下文对象: context= webcl.createContext(webcl.DEVICE_TYPE_GPU);接下来我们将完善上述代码,使得其在不同平台上更加可靠。考虑到有些设备上并未安装GPU需要的OpenCL的运行环境,我们会尝试为CPU设备建立WebCL上下文。当在CPU设备上创建WebCL上下文失败的时候,我们将抛出一个异常。完善后的代码如下所示:try { context = webcl.createContext(webcl.DEVICE_TYPE_GPU);} catch (e) { try {
context =webcl.createContext(webcl.DEVICE_TYPE_CPU); } catch (e) {
alert(&WebCL is not supported by yourdevice!&); }}分配input与output的内存对象为了使过程更加简单直接,我们仍然使用串行的方式构造输入数组。var len = 1000000;var arr1 = new Float32Array(len);for (i = 0; i & i++) arr1[i] =但是,在主机端创建的arr1是无法被kernel直接访问到的。为了让kernel获得输入数据,WebCL上下文对象需要在WebCL设备上分配一块内存空间,并使用arr1中的数据进行初始化。var buf1 = context.createBuffer(webcl.MEM_READ_ONLY,arr1.byteLength, arr1);常量webcl.MEM_READ_ONLY表示我们创建的内存对象对kernel来说是只读的。根据这一信息,WebCL会做一些特殊优化。Kernel同样无法直接将结果输出到Javascript的类型数组中。我们同样需要创建一个内存对象作为结果传递的中介:var buf2 = context.createBuffer(webcl.MEM_WRITE_ONLY, arr1.byteLength);webcl.MEM_WRITE_ONLY与webcl.MEM_READ_ONLY的作用相似。表示我们需要创建一个只写的内存对象。同样,根据这一信息,WebCL会做一些特殊优化。在这里我们仅提供了两个参数,因为并不需要使用先有的类型数组初始化被分配的数组。
创建WebCL kernel程序对象 我们将原有的任务进行拆分,以便使用并行技术同时计算各个子任务。在本例中,我们将原有的任务分割成1,000,000个work item。work item都被分配了不同的ID,该ID从0开始。本例中,每一个work item被分配的任务是从输入的数组中取出一个元素并计算该元素的平方根。Work item执行的逻辑以类C99的语法编写,其内容如下:var source = ’ \__kernel void sqrtPar( \
__global float *buf1, \
__global float *buf2) \{ \ size_t i = get_global_id(0); \ buf2[i] = sqrt(buf1[i]); \}’;var program = context.createProgram(source);source变量存储了WebCLkernel的源代码。我们对这个kernel进行一些说明: 关键字__kernel表示函数sqrtPar()将被“导出”。这样在主机端的Javascript代码中我们可以通过一些方法调用这一函数。这种函数在后续内容中将被称为kernel函数。Kernel函数的返回值必须为void类型。如果一个函数在声明时没有被__kernel关键字修饰,那么该函数在主机端是不可见的,这种函数仅可以在WebCL kernel程序内部被调用。 buf1和buf2将指向我们之前分配的输入内存对象和输出内存对象。OpenCL设备上抽象出了多种不同类型的地址空间,而不同的地址空间的访问速度以及大小是有很大差异的。关键字__global意味着被buf1与buf2指向的数组存在全局地址空间(因为createBuffer()的调用结果是在全局地址空间分配一块内存)。get_global_id()是一个内建的函数,该函数将会根据参数返回work item在对应维度的 ID。本例较为简单,sqrtPar()函数仅仅以一维加载,所以每一个work item的ID通过调用get_global_id(0)获取。在有些情况下,我们可能希望以二维加载WebCLkernel程序,例如一些图像处理程序。在这些例子中,我们使用get_global_id(0)和get_global_id(1)获得图片中workitem处理的像素的横坐标与纵坐标。Sqrt()是另一个内建函数,该函数将计算浮点数的平方根。接下来,我们调用相应接口将WebCL kernel 编译成与设备相关的机器码。 program.build();如果WebCLkernel程序在编译过程中发生了错误,则该函数会抛出一个异常。创建WebCL kernel对象 在一个复杂的kernel源代码中,可能会包含多个kernel函数。一个kernel函数也可能被传入不同参数被多次被调用。kernel函数的名称以及与之相关的参数就被存储在WebCL kernel对象中。下列代码展示了如何创建sqirtPar() kernel函数的WebCL kernel对象。var kernel = program.createKernel(&sqrtPar&);接下来,我们调用相应的API,让buf1与buf2分别指向输入内存对象与输出内存对象。kernel.setArg(0, buf1);kernel.setArg(1, buf2);这里的0 和 1对应着kernel函数的参数列表中参数的位置。
加载WebCL kernel程序 完成上述准备工作后,我们可以将WebCLkernel程序加载到WebCL设备中运行了。首先,我们创建一个消息队列,并将一条加载kernel的命令加入队列,然后加入一条读取内存对象的命令将结果从设备上拷贝到Javascript上下文中。消息队列中的命令将会被提交给OpenCL驱动并执行相应操作。整个过程如下:var queue = context.createCommandQueue();var workDim = 1;var globalWorkOffset =var globalWorkSize = [len];queue.enqueueNDRangeKernel(kernel, workDim, globalWorkOffset, globalWorkSize);var arr2 = new Float32Array(len);var blockingRead =var bufOffset = 0;var bufSize = arr2.byteLqueue.enqueueReadBuffer(buf2, blockingRead, bufOffset, bufSize, arr2); 如前文所述,sqrtPar()以一维的形式被加载,总共1,000,000 work item被分配用来执行该函数(globalWorkSize = [len])。本教程中,globalWorkOffset对计算并无影响,因此只需要以null初始化。blockingRead=true 意味着enqueueReadBuffer()直到读内存命令执行完毕才会返回。因为在这种情况下主线程将被阻塞,因此使用blockingRead并不被推荐。但本教程作为入门篇,将不会涉及异步读取的内容,该部分内容在后续教程中会有涉及。bufOffset以及bufSize定义了内存对象的一个范围,该范围内的数据将被拷贝到arr2中。将各个部分合起来,最后的程序如下所示:&!DOCTYPE html&&html&&body&&script&// Create a WebCL context.try { context = webcl.createContext(webcl.DEVICE_TYPE_GPU);} catch (e) { try {
context =webcl.createContext(webcl.DEVICE_TYPE_CPU); } catch (e) {
alert(&WebCL is not supported by yourdevice!&); }}// Allocate the input and output buffer.var len = 1000000;var arr1 = new Float32Array(len);for (i = 0; i & i++) arr1[i] =var buf1 = context.createBuffer(webcl.MEM_READ_ONLY, arr1.byteLength,arr1);var buf2 = context.createBuffer(webcl.MEM_WRITE_ONLY, arr1.byteLength);// Create and build the WebCL kernel program.var source = ’ \__kernel void sqrtPar( \
__global float *buf1, \
__global float *buf2) \{ \ size_t i = get_global_id(0); \ buf2[i] = sqrt(buf1[i]); \}’;var program = context.createProgram(source);program.build();// Initialize the WebCL kernel object.var kernel = program.createKernel(&sqrtPar&);kernel.setArg(0, buf1);kernel.setArg(1, buf2);// Create a command queue.var queue = context.createCommandQueue();// Enqueue a kernel launch command to spawn 1,000,000// work items in one dimension.var workDim = 1;var globalWorkOffset =var globalWorkSize = [len];queue.enqueueNDRangeKernel(kernel, workDim, globalWorkOffset, globalWorkSize);// Enqueue a buffer read command to get the result.var arr2 = new Float32Array(len);var blockingRead =var bufOffset = 0;var bufSize = arr2.byteLqueue.enqueueReadBuffer(buf2, blockingRead, bufOffset, bufSize, arr2);&/script&&/body&&/html&你可以用你喜欢的方式检查输出结果。Crosswalk(Crosswalk-project) 
 文章为作者独立观点,不代表大不六文章网立场
的最新文章
2015 年 Crosswalk 总结, 涵盖了 Crosswalk 在2015 年增加的新特性, 新平台, 新工具, 以及获得的新的成绩。Crosswalk 强势登场cocos开发者大会!Crosswalk 的介绍 以及在 H5 游戏领域的成果。近期,Crosswalk团队收到了一份由Nightwatch Cybersecurity 发布的安全漏洞报告Crosswalk for Android项目从 17 版本开始将支持全新的下载模式,使用该模式打包的 Crosswalk H5 APP在拥有小体积的同时让开发者获得对 APP 升级的完全控制权,是兼具共享模式与嵌入模式优点的一种新的模式。Crosswalk for Android 从 版本14开始正式支持 WebCL 标准,本篇教程将手把手教你如何把多核处理器的计算能力带入Web领域。Goodbye 2015, Hello 2016。 在2015年的最后一天,深度操作系统 版本15发布,携手Crosswalk Project 跨年2016。Application Showcase 是 Crosswalk 官方网站最新上线的板块,各位使用 Crosswalk制作应用的小伙伴们,用 app 秀出你们的创意吧!2015 年 Crosswalk 总结, 涵盖了 Crosswalk 在2015 年增加的新特性, 新平台, 新工具, 以及获得的新的成绩。Crosswalk 强势登场cocos开发者大会!Crosswalk 的介绍 以及在 H5 游戏领域的成果。Crosswalk 18 稳定版发布, 新增诸多激动人心的新特性。cordova-plugin-crosswalk-webview 1.7.0 同步更新,完美支持 Crosswalk 18 以及 Crosswalk Lite 17!iWeb 峰会上海站, Crosswalk团队带着 demo, 讲座 以及奖品与您相约小南国花园酒店,体验 2016 Web领域最新动态!针对Crosswalk在Cordova平台上的使用教程Crosswalk-projecthttps://crosswalk-project.org/热门文章最新文章Crosswalk-projecthttps://crosswalk-project.org/}

我要回帖

更多关于 万科物业能耗测算 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信