欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2017年06月12日 10:31:46   作者:IT隨筆  
這篇文章主要介紹了Android實(shí)現(xiàn)簡(jiǎn)易計(jì)步器功能隔天步數(shù)清零查看歷史運(yùn)動(dòng)紀(jì)錄,需要的朋友可以參考下

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

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

先來(lái)看下我們需要解決的點(diǎn)有:

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

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

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

          

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

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

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

/** 
 * 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秒進(jìn)行一次存儲(chǔ) 
  private static int saveDuration = 3000; 
  //傳感器 
  private SensorManager sensorManager; 
  //數(shù)據(jù)庫(kù) 
  private StepDataDao stepDataDao; 
  //計(jì)步傳感器類型 0-counter 1-detector 
  private static int stepSensor = -1; 
  //廣播接收 
  private BroadcastReceiver mInfoReceiver; 
  //自定義簡(jiǎn)易計(jì)時(shí)器 
  private TimeCount timeCount; 
  //發(fā)送消息,用來(lái)和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為前臺(tái),不然當(dāng)APP結(jié)束以后很容易被GC給干掉,這也就是大多數(shù)音樂(lè)播放器會(huì)在狀態(tài)欄設(shè)置一個(gè) 
     * 原理大都是相通的 
     */ 
    notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
    //獲取一個(gè)Notification構(gòu)造器 
    builder = new Notification.Builder(this.getApplicationContext()); 
    /** 
     * 設(shè)置點(diǎn)擊通知欄打開(kāi)的界面,此處需要注意了,如果你的計(jì)步界面不在主界面,則需要判斷app是否已經(jīng)啟動(dòng), 
     * 再來(lái)確定跳轉(zhuǎn)頁(yè)面,這里面太多坑,(別問(wè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("加油,要記得勤加運(yùn)動(dòng)"); // 設(shè)置上下文內(nèi)容 
    // 獲取構(gòu)建好的Notification 
    Notification stepNotification = builder.build(); 
    notificationManager.notify(110,stepNotification); 
    // 參數(shù)一:唯一的通知標(biāo)識(shí);參數(shù)二:通知消息。 
    startForeground(110, stepNotification);// 開(kāi)始前臺(tái)服務(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 { 
            //這里負(fù)責(zé)將當(dāng)前的步數(shù)發(fā)送出去,可以在界面或者其他地方獲取,我這里是在MainActivity中獲取來(lái)更新界面 
            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)機(jī)廣播 
    filter.addAction(Intent.ACTION_SHUTDOWN); 
    // 屏幕解鎖廣播 
    filter.addAction(Intent.ACTION_USER_PRESENT); 
    // 當(dāng)長(zhǎng)按電源鍵彈出“關(guān)機(jī)”對(duì)話或者鎖屏?xí)r系統(tǒng)會(huì)發(fā)出這個(gè)廣播 
    // example:有時(shí)候會(huì)用到系統(tǒng)對(duì)話框,權(quán)限可能很高,會(huì)覆蓋在鎖屏界面或者“關(guān)機(jī)”對(duì)話框之上, 
    // 所以監(jiān)聽(tīng)這個(gè)廣播,當(dāng)收到時(shí)就隱藏自己的對(duì)話,如點(diǎn)擊pad右下角部分彈出的對(duì)話框 
    filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 
    //監(jiān)聽(tīng)日期變化 
    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秒一存儲(chǔ) 
            saveDuration = 10000; 
            break; 
          //關(guān)機(jī)廣播,保存好當(dāng)前數(shù)據(jù) 
          case Intent.ACTION_SHUTDOWN: 
            saveStepData(); 
            break; 
          // 屏幕解鎖廣播 
          case Intent.ACTION_USER_PRESENT: 
            saveDuration = 3000; 
            break; 
          // 當(dāng)長(zhǎng)按電源鍵彈出“關(guān)機(jī)”對(duì)話或者鎖屏?xí)r系統(tǒng)會(huì)發(fā)出這個(gè)廣播 
          // example:有時(shí)候會(huì)用到系統(tǒng)對(duì)話框,權(quán)限可能很高,會(huì)覆蓋在鎖屏界面或者“關(guān)機(jī)”對(duì)話框之上, 
          // 所以監(jiān)聽(tīng)這個(gè)廣播,當(dāng)收到時(shí)就隱藏自己的對(duì)話,如點(diǎn)擊pad右下角部分彈出的對(duì)話框 
          case Intent.ACTION_CLOSE_SYSTEM_DIALOGS: 
            saveStepData(); 
            break; 
          //監(jiān)聽(tīng)日期變化 
          case Intent.ACTION_DATE_CHANGED: 
          case Intent.ACTION_TIME_CHANGED: 
          case Intent.ACTION_TIME_TICK: 
            saveStepData(); 
            isNewDay(); 
            break; 
          default: 
            break; 
        } 
      } 
    }; 
    //注冊(cè)廣播 
    registerReceiver(mInfoReceiver, filter); 
  } 
  /** 
   * 初始化當(dāng)天數(shù)據(jù) 
   */ 
  private void initTodayData() { 
    //獲取當(dāng)前時(shí)間 
    CURRENT_DATE = TimeUtil.getCurrentDate(); 
    //獲取數(shù)據(jù)庫(kù) 
    stepDataDao = new StepDataDao(getApplicationContext()); 
    //獲取當(dāng)天的數(shù)據(jù),用于展示 
    StepEntity entity = stepDataDao.getCurDataByDate(CURRENT_DATE); 
    //為空則說(shuō)明還沒(méi)有該天的數(shù)據(jù),有則說(shuō)明已經(jīng)開(kāi)始當(dāng)天的計(jì)步了 
    if (entity == null) { 
      CURRENT_STEP = 0; 
    } else { 
      CURRENT_STEP = Integer.parseInt(entity.getSteps()); 
    } 
  } 
  /** 
   * 監(jiān)聽(tīng)晚上0點(diǎn)變化初始化數(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(); 
    } 
  } 
  /** 
   * 獲取傳感器實(shí)例 
   */ 
  private void getStepDetector() { 
    if (sensorManager != null) { 
      sensorManager = null; 
    } 
    // 獲取傳感器管理器的實(shí)例 
    sensorManager = (SensorManager) this 
        .getSystemService(SENSOR_SERVICE); 
    //android4.4以后可以使用計(jì)步傳感器 
    int VERSION_CODES = Build.VERSION.SDK_INT; 
    if (VERSION_CODES >= 19) { 
      addCountStepListener(); 
    } 
  } 
  /** 
   * 添加傳感器監(jiān)聽(tīng) 
   */ 
  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)前用戶運(yùn)動(dòng)步數(shù),注意:該傳感器只在4.4及以后才有,并且該傳感器記錄的數(shù)據(jù)是從設(shè)備開(kāi)機(jī)以后不斷累加, 
   * 只有當(dāng)用戶關(guān)機(jī)以后,該數(shù)據(jù)才會(huì)清空,所以需要做數(shù)據(jù)保護(hù) 
   * 
   * @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) { 
  } 
  /** 
   * 開(kāi)始倒計(jì)時(shí),去存儲(chǔ)步數(shù)到數(shù)據(jù)庫(kù)中 
   */ 
  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() { 
      // 如果計(jì)時(shí)器正常結(jié)束,則每隔三秒存儲(chǔ)步數(shù)到數(shù)據(jù)庫(kù) 
      timeCount.cancel(); 
      saveStepData(); 
      startTimeCount(); 
    } 
  } 
  /** 
   * 保存當(dāng)天的數(shù)據(jù)到數(shù)據(jù)庫(kù)中,并去刷新通知欄 
   */ 
  private void saveStepData() { 
    //查詢數(shù)據(jù)庫(kù)中的數(shù)據(jù) 
    StepEntity entity = stepDataDao.getCurDataByDate(CURRENT_DATE); 
    //為空則說(shuō)明還沒(méi)有該天的數(shù)據(jù),有則說(shuō)明已經(jīng)開(kāi)始當(dāng)天的計(jì)步了 
    if (entity == null) { 
      //沒(méi)有則新建一條數(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("加油,要記得勤加運(yùn)動(dòng)"); // 設(shè)置上下文內(nèi)容  
    // 獲取構(gòu)建好的Notification 
    Notification stepNotification = builder.build(); 
    //調(diào)用更新 
    notificationManager.notify(110,stepNotification); 
  } 
  @Override 
  public void onDestroy() { 
    super.onDestroy(); 
    //主界面中需要手動(dòng)調(diào)用stop方法service才會(huì)結(jié)束 
    stopForeground(true); 
    unregisterReceiver(mInfoReceiver); 
  } 
  @Override 
  public boolean onUnbind(Intent intent) { 
    return super.onUnbind(intent); 
  } 
} 

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

主要要說(shuō)的就是以上了,源碼在這里源碼點(diǎn)我點(diǎn)我

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

相關(guān)文章

最新評(píng)論