AndroidWearで心拍数をリアルタイムに取得する!

  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る

AndroidWearの心拍センサを使って、心拍数をリアルタイムに表示するアプリを作ります。

鼓動のドクドクも表現してみます。

はじめに

AndroidWearで心拍数を取得して表示するサンプルアプリを作っていきます.

検証した実機は
Moto360 1st Gen(Wear1.0)
HUAWEI WATCH(Wear2.0)
の二つです.

手順

1.センサーマネージャの取得

2.イベントリスナーの登録

3.心拍数の取得

4.心拍数を表示

という流れになります.

1.センサーマネージャの取得

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
    mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}

2.SensorEventListenerインタフェースの実装

public class MainActivity extends WearableActivity implements SensorEventListener{
onSensorChanged

心拍センサの値に変化があると、ここの部分が実行されます。

心拍数を表示する処理を記述します。

onAccuracyChanged

センサの精度に変更があったときに実行されます。

3.心拍数の取得

    @Override
    public void onSensorChanged(SensorEvent event) {
        //ここで変数宣言すると,起動中は破棄されずメモリリークする
        if(set==false)textView.setTextSize(60.0f);
        if (event.sensor.getType() == Sensor.TYPE_HEART_RATE) {
            hb = event.values[0];
            //心拍数を表示
            textView.setText(""+(int)hb);
            set = true;
        }
    }

心拍数はevent.values[0];に格納されます。

4.心拍数を表示

心拍数は一分間の鼓動の回数です。

鼓動の間隔を求め、用意したハートの画像の大きさを変えることで心臓のドクドクする鼓動を表現します。

上のハートの画像をheart.pngとしてres/drawable内に保存します。

    public void update(){
        if(set) {
            if (isDisp) {
                backGround.setBackgroundColor(Color.argb(80, 231, 232, 226));
                //heartTextView.setTextSize(100.0f);
                textView.setTextSize(60.0f);
                ImageView img = (ImageView) findViewById(R.id.imageView);
                Resources res = getResources();
                Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.heart);
                // bitmapの画像を250*250で作成する
                Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, 250, 250, false);
                img.setImageBitmap(bitmap2);

            } else {
                backGround.setBackgroundColor(Color.argb(10, 231, 232, 226));
                //heartTextView.setTextSize(800.0f);
                textView.setTextSize(70.0f);
                ImageView img = (ImageView) findViewById(R.id.imageView);
                Resources res = getResources();
                Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.heart);
                // bitmapの画像を300*300で作成する
                Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, 300, 300, false);
                img.setImageBitmap(bitmap2);
            }
        }
        isDisp = !isDisp;
    }


    //一定時間後にupdateを呼ぶためのオブジェクト
    class LoopEngine extends Handler {
        private boolean isUpdate;
        public void start(){
            this.isUpdate = true;
            handleMessage(new Message());
        }
        public void stop(){
            this.isUpdate = false;
        }
        @Override
        public void handleMessage(Message msg) {
            this.removeMessages(0);//既存のメッセージは削除
            if(this.isUpdate){
                MainActivity.this.update();//自信が発したメッセージを取得してupdateを実行
                sendMessageDelayed(obtainMessage(0), (long)(60/hb*1000));//鼓動の間隔でメッセージを出力
            }
        }
    };

最後にソースコード

MainActivity.java

package yokohama.mio.heartbeat;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.wearable.activity.WearableActivity;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import static android.graphics.Typeface.BOLD;
import static android.graphics.Typeface.DEFAULT_BOLD;

public class MainActivity extends WearableActivity implements SensorEventListener{
    private final String TAG = MainActivity.class.getName();
    private SensorManager mSensorManager;
    public float hb=100.0f;
    private TextView textView;
    private TextView heartTextView;
    public View backGround;
    public boolean isDisp=true;
    private LoopEngine loopEngine = new LoopEngine();
    public ImageView imageView;
    boolean set = false;


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

        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        textView = (TextView) findViewById(R.id.text);
        heartTextView = (TextView) findViewById(R.id.text_heart);
        backGround = (View) findViewById(R.id.View);
        textView.setTextSize(20.0f);
        heartTextView.setTextSize(0.0f);
        loopEngine.start();
        //heartTextView.setTextColor(Color.argb(80, 67, 135, 233));
        textView.setTextColor(Color.argb(255, 140, 140, 140));
        textView.setTypeface(Typeface.create(DEFAULT_BOLD, BOLD));

    }
    private LinearLayout.LayoutParams createParam(int w, int h){
        return new LinearLayout.LayoutParams(w, h);
    }
    @Override
    protected void onResume() {
        super.onResume();
        Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
        mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
    }
    @Override
    protected void onPause(){
        super.onPause();
        mSensorManager.unregisterListener(this);
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        //ここで変数宣言すると,起動中は破棄されずメモリリークする
        if(set==false)textView.setTextSize(60.0f);
        if (event.sensor.getType() == Sensor.TYPE_HEART_RATE) {
            hb = event.values[0];
            textView.setText(""+(int)hb);
            set = true;
        }
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        Log.d(TAG,"onAccuracyChanged!!");
    }


    public void update(){
        if(set) {
            if (isDisp) {
                backGround.setBackgroundColor(Color.argb(80, 231, 232, 226));
                //heartTextView.setTextSize(100.0f);
                textView.setTextSize(60.0f);
                ImageView img = (ImageView) findViewById(R.id.imageView);
                Resources res = getResources();
                Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.heart);
                // bitmapの画像を250*250で作成する
                Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, 250, 250, false);
                img.setImageBitmap(bitmap2);

            } else {
                backGround.setBackgroundColor(Color.argb(10, 231, 232, 226));
                //heartTextView.setTextSize(800.0f);
                textView.setTextSize(70.0f);
                ImageView img = (ImageView) findViewById(R.id.imageView);
                Resources res = getResources();
                Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.heart);
                // bitmapの画像を300*300で作成する
                Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, 300, 300, false);
                img.setImageBitmap(bitmap2);
            }
        }
        isDisp = !isDisp;
    }


    //一定時間後にupdateを呼ぶためのオブジェクト
    class LoopEngine extends Handler {
        private boolean isUpdate;
        public void start(){
            this.isUpdate = true;
            handleMessage(new Message());
        }
        public void stop(){
            this.isUpdate = false;
        }
        @Override
        public void handleMessage(Message msg) {
            this.removeMessages(0);//既存のメッセージは削除
            if(this.isUpdate){
                MainActivity.this.update();//自信が発したメッセージを取得してupdateを実行
                sendMessageDelayed(obtainMessage(0), (long)(60/hb*1000));//鼓動の間隔でメッセージを出力
            }
        }
    };
}

main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="yokohama.mio.heartbeat.MainActivity"
    tools:deviceIds="wear">

    <View
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:id="@+id/View"
        android:layout_alignParentBottom="true"
        android:layout_gravity="center_vertical|center_horizontal"/>
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/heart"
        android:scaleType="center"
        android:contentDescription="heart"
        android:layout_gravity="center_vertical|center_horizontal" />
    <TextView
        android:id="@+id/text_heart"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_box="all"
        android:text="♥"
        android:gravity="center_vertical|center_horizontal" />
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_box="all"
        android:text="心拍数測定中\nちょっと待ってね"
        android:textSize="40sp"
        android:gravity="center_vertical|center_horizontal"
        android:textColor="@color/black_54p"/>


</android.support.wearable.view.BoxInsetLayout>

APKはここからダウンロードできます。

参考

Handlerを使ったカウントアップタイマー(ストップウォッチ)|初心者の初心者のためのAndroidアプリ開発!

  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る

SNSでもご購読できます。

コメントを残す

*