国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android實現(xiàn)簡易計步器功能隔天步數(shù)清零查看歷史運動紀(jì)錄

2019-12-12 02:42:04
字體:
供稿:網(wǎng)友

最近需要用到計步功能,這可難壞我了,iOS端倒好,有自帶的計步功能,讓我驚訝的是連已爬樓層都給做好了,只需要調(diào)接口便可獲得數(shù)據(jù),我有一句MMP,我很想講。

但是抱怨歸抱怨,功能還是得事先的去實現(xiàn),微信運動,樂動力,都還不錯,尤其是樂動力的計步功能真的非常的強大,在UI域用戶與用戶交互也做得非常棒,黨來內(nèi)需當(dāng)連續(xù)運動十步后開始計步。本想著去找他們實現(xiàn)的算法然后拿來用,但很明顯這是不可能的。后來我搜了很多資料發(fā)現(xiàn),在Android4.4 Kitkat 新增的STEP DETECTOR 以及 STEP COUNTER傳感器。但是!Android的這個傳感器雖然可以計步,但是所記錄的步數(shù)是從你開機之時開始計算,不斷累加,隔天也不會清零,并且,一旦關(guān)機后,傳感器記錄的數(shù)據(jù)也就清空了!這就很尷尬了,不過既然直接使用傳感器數(shù)據(jù)不行,那我們就自己動手,將數(shù)據(jù)按天來保存~接下來進入正題,皮皮猿,我們走起~

先來看下我們需要解決的點有:

1、步數(shù)從開機之后不斷累加,關(guān)機之后便清零,步數(shù)不能隔天清零

2、不能查看歷史數(shù)據(jù)

這就好辦了。我們只需將當(dāng)前傳感器記錄的步數(shù)以每天為單位存進數(shù)據(jù)庫,如果更新的步數(shù)為當(dāng)天的則去更新數(shù)據(jù)庫!先來看下我的界面(Demo在文章最后):

          

第一二張圖為界面效果圖,數(shù)據(jù)均是從數(shù)據(jù)取出繪制在界面上,第三張圖為設(shè)置前臺進程時所設(shè)置的Notification樣式,當(dāng)然了這個可以去自定義樣式,再此我就不詳細解釋了。

工程的目錄結(jié)構(gòu)如下:

其中主要的代碼都在StepService.class 中了,其中注釋也都非常詳細,我就直接放代碼了:

/**  * Created by fySpring  * Date : 2017/3/24  * To do :  */ public class StepService extends Service implements SensorEventListener {   public static final String TAG = "StepService";   //當(dāng)前日期   private static String CURRENT_DATE;   //當(dāng)前步數(shù)   private int CURRENT_STEP;   //3秒進行一次存儲   private static int saveDuration = 3000;   //傳感器   private SensorManager sensorManager;   //數(shù)據(jù)庫   private StepDataDao stepDataDao;   //計步傳感器類型 0-counter 1-detector   private static int stepSensor = -1;   //廣播接收   private BroadcastReceiver mInfoReceiver;   //自定義簡易計時器   private TimeCount timeCount;   //發(fā)送消息,用來和Service之間傳遞步數(shù)   private Messenger messenger = new Messenger(new MessengerHandler());   //是否有當(dāng)天的記錄   private boolean hasRecord;   //未記錄之前的步數(shù)   private int hasStepCount;   //下次記錄之前的步數(shù)   private int previousStepCount;   private Notification.Builder builder;   private NotificationManager notificationManager;   private Intent nfIntent;   @Override   public void onCreate() {     super.onCreate();     initBroadcastReceiver();     new Thread(new Runnable() {       public void run() {         getStepDetector();       }     }).start();     startTimeCount();     initTodayData();   }   @Nullable   @Override   public IBinder onBind(Intent intent) {     return messenger.getBinder();   }   @Override   public int onStartCommand(Intent intent, int flags, int startId) {     /**      * 此處設(shè)將Service為前臺,不然當(dāng)APP結(jié)束以后很容易被GC給干掉,這也就是大多數(shù)音樂播放器會在狀態(tài)欄設(shè)置一個      * 原理大都是相通的      */     notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);     //獲取一個Notification構(gòu)造器     builder = new Notification.Builder(this.getApplicationContext());     /**      * 設(shè)置點擊通知欄打開的界面,此處需要注意了,如果你的計步界面不在主界面,則需要判斷app是否已經(jīng)啟動,      * 再來確定跳轉(zhuǎn)頁面,這里面太多坑,(別問我為什么知道 - -)      * 總之有需要的可以和我交流      */     nfIntent = new Intent(this, MainActivity.class);     builder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 設(shè)置PendingIntent         .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) // 設(shè)置下拉列表中的圖標(biāo)(大圖標(biāo))         .setContentTitle("今日步數(shù)"+CURRENT_STEP+"步") // 設(shè)置下拉列表里的標(biāo)題         .setSmallIcon(R.mipmap.ic_launcher) // 設(shè)置狀態(tài)欄內(nèi)的小圖標(biāo)         .setContentText("加油,要記得勤加運動"); // 設(shè)置上下文內(nèi)容     // 獲取構(gòu)建好的Notification     Notification stepNotification = builder.build();     notificationManager.notify(110,stepNotification);     // 參數(shù)一:唯一的通知標(biāo)識;參數(shù)二:通知消息。     startForeground(110, stepNotification);// 開始前臺服務(wù)     return START_STICKY;   }   /**    * 自定義handler    */   private class MessengerHandler extends Handler {     @Override     public void handleMessage(Message msg) {       switch (msg.what) {         case Constant.MSG_FROM_CLIENT:           try {             //這里負責(zé)將當(dāng)前的步數(shù)發(fā)送出去,可以在界面或者其他地方獲取,我這里是在MainActivity中獲取來更新界面             Messenger messenger = msg.replyTo;             Message replyMsg = Message.obtain(null, Constant.MSG_FROM_SERVER);             Bundle bundle = new Bundle();             bundle.putInt("steps", CURRENT_STEP);             replyMsg.setData(bundle);             messenger.send(replyMsg);           } catch (RemoteException e) {             e.printStackTrace();           }           break;         default:           super.handleMessage(msg);       }     }   }   /**    * 初始化廣播    */   private void initBroadcastReceiver() {     final IntentFilter filter = new IntentFilter();     // 屏幕滅屏廣播     filter.addAction(Intent.ACTION_SCREEN_OFF);     //關(guān)機廣播     filter.addAction(Intent.ACTION_SHUTDOWN);     // 屏幕解鎖廣播     filter.addAction(Intent.ACTION_USER_PRESENT);     // 當(dāng)長按電源鍵彈出“關(guān)機”對話或者鎖屏?xí)r系統(tǒng)會發(fā)出這個廣播     // example:有時候會用到系統(tǒng)對話框,權(quán)限可能很高,會覆蓋在鎖屏界面或者“關(guān)機”對話框之上,     // 所以監(jiān)聽這個廣播,當(dāng)收到時就隱藏自己的對話,如點擊pad右下角部分彈出的對話框     filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);     //監(jiān)聽日期變化     filter.addAction(Intent.ACTION_DATE_CHANGED);     filter.addAction(Intent.ACTION_TIME_CHANGED);     filter.addAction(Intent.ACTION_TIME_TICK);     mInfoReceiver = new BroadcastReceiver() {       @Override       public void onReceive(Context context, Intent intent) {         String action = intent.getAction();         switch (action) {           // 屏幕滅屏廣播           case Intent.ACTION_SCREEN_OFF:             //屏幕熄滅改為10秒一存儲             saveDuration = 10000;             break;           //關(guān)機廣播,保存好當(dāng)前數(shù)據(jù)           case Intent.ACTION_SHUTDOWN:             saveStepData();             break;           // 屏幕解鎖廣播           case Intent.ACTION_USER_PRESENT:             saveDuration = 3000;             break;           // 當(dāng)長按電源鍵彈出“關(guān)機”對話或者鎖屏?xí)r系統(tǒng)會發(fā)出這個廣播           // example:有時候會用到系統(tǒng)對話框,權(quán)限可能很高,會覆蓋在鎖屏界面或者“關(guān)機”對話框之上,           // 所以監(jiān)聽這個廣播,當(dāng)收到時就隱藏自己的對話,如點擊pad右下角部分彈出的對話框           case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:             saveStepData();             break;           //監(jiān)聽日期變化           case Intent.ACTION_DATE_CHANGED:           case Intent.ACTION_TIME_CHANGED:           case Intent.ACTION_TIME_TICK:             saveStepData();             isNewDay();             break;           default:             break;         }       }     };     //注冊廣播     registerReceiver(mInfoReceiver, filter);   }   /**    * 初始化當(dāng)天數(shù)據(jù)    */   private void initTodayData() {     //獲取當(dāng)前時間     CURRENT_DATE = TimeUtil.getCurrentDate();     //獲取數(shù)據(jù)庫     stepDataDao = new StepDataDao(getApplicationContext());     //獲取當(dāng)天的數(shù)據(jù),用于展示     StepEntity entity = stepDataDao.getCurDataByDate(CURRENT_DATE);     //為空則說明還沒有該天的數(shù)據(jù),有則說明已經(jīng)開始當(dāng)天的計步了     if (entity == null) {       CURRENT_STEP = 0;     } else {       CURRENT_STEP = Integer.parseInt(entity.getSteps());     }   }   /**    * 監(jiān)聽晚上0點變化初始化數(shù)據(jù)    */   private void isNewDay() {     String time = "00:00";     if (time.equals(new SimpleDateFormat("HH:mm").format(new Date())) ||         !CURRENT_DATE.equals(TimeUtil.getCurrentDate())) {       initTodayData();     }   }   /**    * 獲取傳感器實例    */   private void getStepDetector() {     if (sensorManager != null) {       sensorManager = null;     }     // 獲取傳感器管理器的實例     sensorManager = (SensorManager) this         .getSystemService(SENSOR_SERVICE);     //android4.4以后可以使用計步傳感器     int VERSION_CODES = Build.VERSION.SDK_INT;     if (VERSION_CODES >= 19) {       addCountStepListener();     }   }   /**    * 添加傳感器監(jiān)聽    */   private void addCountStepListener() {     Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);     Sensor detectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);     if (countSensor != null) {       stepSensor = 0;       sensorManager.registerListener(StepService.this, countSensor, SensorManager.SENSOR_DELAY_NORMAL);     } else if (detectorSensor != null) {       stepSensor = 1;       sensorManager.registerListener(StepService.this, detectorSensor, SensorManager.SENSOR_DELAY_NORMAL);     }   }   /**    * 由傳感器記錄當(dāng)前用戶運動步數(shù),注意:該傳感器只在4.4及以后才有,并且該傳感器記錄的數(shù)據(jù)是從設(shè)備開機以后不斷累加,    * 只有當(dāng)用戶關(guān)機以后,該數(shù)據(jù)才會清空,所以需要做數(shù)據(jù)保護    *    * @param event    */   @Override   public void onSensorChanged(SensorEvent event) {     if (stepSensor == 0) {       int tempStep = (int) event.values[0];       if (!hasRecord) {         hasRecord = true;         hasStepCount = tempStep;       } else {         int thisStepCount = tempStep - hasStepCount;         CURRENT_STEP += (thisStepCount - previousStepCount);         previousStepCount = thisStepCount;       }     } else if (stepSensor == 1) {       if (event.values[0] == 1.0) {         CURRENT_STEP++;       }     }   }   @Override   public void onAccuracyChanged(Sensor sensor, int accuracy) {   }   /**    * 開始倒計時,去存儲步數(shù)到數(shù)據(jù)庫中    */   private void startTimeCount() {     timeCount = new TimeCount(saveDuration, 1000);     timeCount.start();   }   private class TimeCount extends CountDownTimer {     /**      * @param millisInFuture  The number of millis in the future from the call      *             to {@link #start()} until the countdown is done and {@link #onFinish()}      *             is called.      * @param countDownInterval The interval along the way to receive      *             {@link #onTick(long)} callbacks.      */     public TimeCount(long millisInFuture, long countDownInterval) {       super(millisInFuture, countDownInterval);     }     @Override     public void onTick(long millisUntilFinished) {     }     @Override     public void onFinish() {       // 如果計時器正常結(jié)束,則每隔三秒存儲步數(shù)到數(shù)據(jù)庫       timeCount.cancel();       saveStepData();       startTimeCount();     }   }   /**    * 保存當(dāng)天的數(shù)據(jù)到數(shù)據(jù)庫中,并去刷新通知欄    */   private void saveStepData() {     //查詢數(shù)據(jù)庫中的數(shù)據(jù)     StepEntity entity = stepDataDao.getCurDataByDate(CURRENT_DATE);     //為空則說明還沒有該天的數(shù)據(jù),有則說明已經(jīng)開始當(dāng)天的計步了     if (entity == null) {       //沒有則新建一條數(shù)據(jù)       entity = new StepEntity();       entity.setCurDate(CURRENT_DATE);       entity.setSteps(String.valueOf(CURRENT_STEP));       stepDataDao.addNewData(entity);     } else {       //有則更新當(dāng)前的數(shù)據(jù)       entity.setSteps(String.valueOf(CURRENT_STEP));       stepDataDao.updateCurData(entity);     }     builder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 設(shè)置PendingIntent         .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher)) // 設(shè)置下拉列表中的圖標(biāo)(大圖標(biāo))         .setContentTitle("今日步數(shù)"+CURRENT_STEP+"步") // 設(shè)置下拉列表里的標(biāo)題         .setSmallIcon(R.mipmap.ic_launcher) // 設(shè)置狀態(tài)欄內(nèi)的小圖標(biāo)         .setContentText("加油,要記得勤加運動"); // 設(shè)置上下文內(nèi)容      // 獲取構(gòu)建好的Notification     Notification stepNotification = builder.build();     //調(diào)用更新     notificationManager.notify(110,stepNotification);   }   @Override   public void onDestroy() {     super.onDestroy();     //主界面中需要手動調(diào)用stop方法service才會結(jié)束     stopForeground(true);     unregisterReceiver(mInfoReceiver);   }   @Override   public boolean onUnbind(Intent intent) {     return super.onUnbind(intent);   } } 

其中關(guān)于四大組件之一的Service也有很多要去學(xué)習(xí)的,這幾天也是惡補了一下,算是彌補當(dāng)年在學(xué)校沒有仔細學(xué)習(xí)這一塊的遺憾吧 - -

主要要說的就是以上了,源碼在這里源碼點我點我

以上所述是小編給大家介紹的Android實現(xiàn)簡易計步器功能隔天步數(shù)清零查看歷史運動紀(jì)錄,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對武林網(wǎng)網(wǎng)站的支持!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 睢宁县| 灵宝市| 卢龙县| 扶风县| 雷州市| 玛沁县| 平定县| 七台河市| 沛县| 深圳市| 池州市| 祁东县| 镇原县| 会宁县| 青海省| 洛南县| 荣成市| 安庆市| 延长县| 新蔡县| 长白| 巴南区| 高邮市| 玉龙| 永修县| 辛集市| 闽侯县| 名山县| 包头市| 当阳市| 天等县| 阿合奇县| 尚义县| 西乌| 珠海市| 峨眉山市| 柘城县| 甘肃省| 松桃| 松原市| 蒲城县|