标签:
1.相信越来越多的人开始注重健康而运动,那怎样才能更有动力呢,用数据记录下来,朋友之间相互比拼会更有东西。这也是现在计步器流行的主要原因之一!
2.原理,其实大部分的应用都是通过手机的重力传感器的监听来做的!你会发现,几乎所有计步器,只要晃动手机,都可以记步,因为晃动中就触发了重力传感器!
今天我们就来解析一下由Levente Bagi创建的计步器Podometer源码!网上也有很多其他的,但这个算是比较完整的,包含了各项配置,灵敏度,步长,甚至语音功能提醒(目前只支持部分语言:英语,法语。。,不支持中文),看完之后我相信你不仅学习到了计步器功能,还对系统喜好设置PreferenceActivity使用,和语音有所了解,也可以从中看出国外开发者是怎样的一种思维方式来开发的!
首先,主页面Pedometer
package cq.cake.pedometer;/* * Pedometer - Android App * Copyright (C) 2009 Levente Bagi * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.preference.PreferenceManager; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; /** * 计步器主页面 */ public class Pedometer extends AppCompatActivity { private static final String TAG = "Pedometer"; private SharedPreferences mSettings;//共同的偏好 private PedometerSettings mPedometerSettings;//计步器设置参数 private Utils mUtils;//语音工具集 private TextView mStepValueView; private TextView mPaceValueView; private TextView mDistanceValueView; private TextView mSpeedValueView; private TextView mCaloriesValueView; TextView mDesiredPaceView;//所需的步伐 private int mStepValue;//mStepValueView的值 private int mPaceValue;//mPaceValueView的值 private float mDistanceValue;//mDistanceValueView的值 private float mSpeedValue;//mSpeedValueView的值 private int mCaloriesValue;//mCaloriesValueView的值 private float mDesiredPaceOrSpeed;//所需的步速(步/分钟)或速度(km/h) private int mMaintain;//是否是步行或跑步 private boolean mIsMetric;//公制和米制切换标志 private float mMaintainInc;//爬山数值 private boolean mQuitting = false; //应用是否退出 // Set when user selected Quit from menu, can be used by onPause, onStop, onDestroy /** * True, when service is running. */ private boolean mIsRunning;//程序是否运行的标志位 /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { Log.i(TAG, "[ACTIVITY] onCreate"); super.onCreate(savedInstanceState); mStepValue = 0; mPaceValue = 0; setContentView(R.layout.main); mUtils = Utils.getInstance(); } //开始函数,重写该函数,加入日志。 // @Override // protected void onStart() { // Log.i(TAG, "[ACTIVITY] onStart"); // super.onStart(); // } //重写回复函数 @Override protected void onResume() { Log.i(TAG, "[ACTIVITY] onResume"); super.onResume(); //得到当前应用的喜好设置资源 mSettings = PreferenceManager.getDefaultSharedPreferences(this); mPedometerSettings = new PedometerSettings(mSettings); mUtils.setSpeak(mSettings.getBoolean("speak", false)); // 读取当前服务是否正在运行 mIsRunning = mPedometerSettings.isServiceRunning(); // 如果服务没有运行,且是新的一轮记步开始,就开启服务,并绑定服务 if (!mIsRunning && mPedometerSettings.isNewStart()) { startStepService(); bindStepService(); } //否则就只是绑定服务 else if (mIsRunning) { bindStepService(); } //暂停服务,并将时间戳清0 mPedometerSettings.clearServiceRunning(); //显示步数的控件 mStepValueView = (TextView) findViewById(R.id.step_value); mPaceValueView = (TextView) findViewById(R.id.pace_value); mDistanceValueView = (TextView) findViewById(R.id.distance_value); mSpeedValueView = (TextView) findViewById(R.id.speed_value); mCaloriesValueView = (TextView) findViewById(R.id.calories_value); mDesiredPaceView = (TextView) findViewById(R.id.desired_pace_value); //根据偏好设置参数,是公里还是英里来显示不同的文本 mIsMetric = mPedometerSettings.isMetric(); ((TextView) findViewById(R.id.distance_units)).setText(getString( mIsMetric ? R.string.kilometers : R.string.miles )); ((TextView) findViewById(R.id.speed_units)).setText(getString( mIsMetric ? R.string.kilometers_per_hour : R.string.miles_per_hour )); //根据设置是静止,走,快走来确定是否要显示速度控制 mMaintain = mPedometerSettings.getMaintainOption(); ((LinearLayout) this.findViewById(R.id.desired_pace_control)).setVisibility( mMaintain != PedometerSettings.M_NONE ? View.VISIBLE : View.GONE ); if (mMaintain == PedometerSettings.M_PACE) { mMaintainInc = 5f; mDesiredPaceOrSpeed = (float)mPedometerSettings.getDesiredPace(); } else if (mMaintain == PedometerSettings.M_SPEED) { mDesiredPaceOrSpeed = mPedometerSettings.getDesiredSpeed(); mMaintainInc = 0.1f; } Button button1 = (Button) findViewById(R.id.button_desired_pace_lower); button1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mDesiredPaceOrSpeed -= mMaintainInc; mDesiredPaceOrSpeed = Math.round(mDesiredPaceOrSpeed * 10) / 10f; displayDesiredPaceOrSpeed(); setDesiredPaceOrSpeed(mDesiredPaceOrSpeed); } }); Button button2 = (Button) findViewById(R.id.button_desired_pace_raise); button2.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mDesiredPaceOrSpeed += mMaintainInc; mDesiredPaceOrSpeed = Math.round(mDesiredPaceOrSpeed * 10) / 10f; displayDesiredPaceOrSpeed(); setDesiredPaceOrSpeed(mDesiredPaceOrSpeed); } }); //根据是步行还是跑步来显示步数还是速度 if (mMaintain != PedometerSettings.M_NONE) { ((TextView) findViewById(R.id.desired_pace_label)).setText( mMaintain == PedometerSettings.M_PACE ? R.string.desired_pace : R.string.desired_speed ); } displayDesiredPaceOrSpeed(); } private void displayDesiredPaceOrSpeed() { if (mMaintain == PedometerSettings.M_PACE) { mDesiredPaceView.setText("步行速度:" + (int)mDesiredPaceOrSpeed); } else { mDesiredPaceView.setText("跑步速度:" + mDesiredPaceOrSpeed); } } /** * 暂停时,也把服务解绑,并保存 */ @Override protected void onPause() { Log.i(TAG, "[ACTIVITY] onPause"); if (mIsRunning) { unbindStepService(); } //如果退出应用就保持服务,去掉时间搓 if (mQuitting) { mPedometerSettings.saveServiceRunningWithNullTimestamp(mIsRunning); } else { mPedometerSettings.saveServiceRunningWithTimestamp(mIsRunning); } super.onPause(); savePaceSetting(); } @Override protected void onStop() { Log.i(TAG, "[ACTIVITY] onStop"); super.onStop(); } protected void onDestroy() { Log.i(TAG, "[ACTIVITY] onDestroy"); super.onDestroy(); } @SuppressLint("MissingSuperCall") protected void onRestart() { Log.i(TAG, "[ACTIVITY] onRestart"); super.onDestroy(); } /** * 设置想要的步行还是跑 * mMaintain:我的主观意思:是步行还是跑 * @param desiredPaceOrSpeed */ private void setDesiredPaceOrSpeed(float desiredPaceOrSpeed) { if (mService != null) { if (mMaintain == PedometerSettings.M_PACE) { mService.setDesiredPace((int)desiredPaceOrSpeed); } else if (mMaintain == PedometerSettings.M_SPEED) { mService.setDesiredSpeed(desiredPaceOrSpeed); } } } private void savePaceSetting() { mPedometerSettings.savePaceOrSpeedSetting(mMaintain, mDesiredPaceOrSpeed); } private StepService mService; 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 = null; } }; /** * 开启记步服务 */ private void startStepService() { if (! mIsRunning) { Log.i(TAG, "[SERVICE] Start"); mIsRunning = true; startService(new Intent(Pedometer.this, StepService.class)); } } private void bindStepService() { Log.i(TAG, "[SERVICE] Bind"); bindService(new Intent(Pedometer.this, StepService.class), mConnection, Context.BIND_AUTO_CREATE + Context.BIND_DEBUG_UNBIND); } private void unbindStepService() { Log.i(TAG, "[SERVICE] Unbind"); unbindService(mConnection); } private void stopStepService() { Log.i(TAG, "[SERVICE] Stop"); if (mService != null) { Log.i(TAG, "[SERVICE] stopService"); stopService(new Intent(Pedometer.this, StepService.class)); } mIsRunning = false; } private void resetValues(boolean updateDisplay) { //如果服务不为null且正在跑 if (mService != null && mIsRunning) { mService.resetValues(); } else { mStepValueView.setText("0"); mPaceValueView.setText("0"); mDistanceValueView.setText("0"); mSpeedValueView.setText("0"); mCaloriesValueView.setText("0"); SharedPreferences state = getSharedPreferences("state", 0); SharedPreferences.Editor stateEditor = state.edit(); if (updateDisplay) { stateEditor.putInt("steps", 0); stateEditor.putInt("pace", 0); stateEditor.putFloat("distance", 0); stateEditor.putFloat("speed", 0); stateEditor.putFloat("calories", 0); stateEditor.commit(); } } } private static final int MENU_SETTINGS = 8; private static final int MENU_QUIT = 9; private static final int MENU_PAUSE = 1; private static final int MENU_RESUME = 2; private static final int MENU_RESET = 3; /* Creates the menu items */ public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); if (mIsRunning) { menu.add(0, MENU_PAUSE, 0, R.string.pause) .setIcon(android.R.drawable.ic_media_pause) .setShortcut('1', 'p'); } else { menu.add(0, MENU_RESUME, 0, R.string.resume) .setIcon(android.R.drawable.ic_media_play) .setShortcut('1', 'p'); } menu.add(0, MENU_RESET, 0, R.string.reset) .setIcon(android.R.drawable.ic_menu_close_clear_cancel) .setShortcut('2', 'r'); menu.add(0, MENU_SETTINGS, 0, R.string.settings) .setIcon(android.R.drawable.ic_menu_preferences) .setShortcut('8', 's') .setIntent(new Intent(this, Settings.class)); menu.add(0, MENU_QUIT, 0, R.string.quit) .setIcon(android.R.drawable.ic_lock_power_off) .setShortcut('9', 'q'); return true; } /* Handles item selections */ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_PAUSE: unbindStepService(); stopStepService(); return true; case MENU_RESUME: startStepService(); bindStepService(); return true; case MENU_RESET: resetValues(true); return true; case MENU_QUIT: resetValues(false); unbindStepService(); stopStepService(); mQuitting = true; finish(); return true; } return false; } // TODO: unite all into 1 type of message 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)); } }; private static final int STEPS_MSG = 1; private static final int PACE_MSG = 2; private static final int DISTANCE_MSG = 3; private static final int SPEED_MSG = 4; private static final int CALORIES_MSG = 5; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case STEPS_MSG: mStepValue = (int)msg.arg1; mStepValueView.setText("" + mStepValue); break; case PACE_MSG: mPaceValue = msg.arg1; if (mPaceValue <= 0) { mPaceValueView.setText("0"); } else { mPaceValueView.setText("" + (int)mPaceValue); } break; case DISTANCE_MSG: mDistanceValue = ((int)msg.arg1)/1000f; if (mDistanceValue <= 0) { mDistanceValueView.setText("0"); } else { mDistanceValueView.setText( ("" + (mDistanceValue + 0.000001f)).substring(0, 5) ); } break; case SPEED_MSG: mSpeedValue = ((int)msg.arg1)/1000f; if (mSpeedValue <= 0) { mSpeedValueView.setText("0"); } else { mSpeedValueView.setText( ("" + (mSpeedValue + 0.000001f)).substring(0, 4) ); } break; case CALORIES_MSG: mCaloriesValue = msg.arg1; if (mCaloriesValue <= 0) { mCaloriesValueView.setText("0"); } else { mCaloriesValueView.setText("" + (int)mCaloriesValue); } break; default: super.handleMessage(msg); } } }; }
标签:
原文地址:http://blog.csdn.net/xiaoshubing/article/details/51330132