예전에는 프로그램을 만들 때 기본적인 초기 값 설정과 사용 중 추가로 발생 하는 환경 정보들을 파일로 만들거나 쿠키에 넣어 관리를 했었는데 매번 파일을 읽어와 파싱 하고 적용하는 번거로운 작업들을 해야 했습니다. 

그런 작업들을 경량화된 데이터베이스인 SQLite를 이용하여 관리를 하면 좀더 편하게 작업이 될 수 있고 프로그램에서 발생 하는 여러 가지 데이터와 로그등도 쉽게 관리할 수 있습니다. 

사실 sqlite도 파일 형태의 데이터 베이스 이기 때문에 파일로 관리할 때 처럼 동시에 쓰기를 하면 오류가 발생 합니다.




1. SQLite 설치


1.1 SQLite 다운로드


제일 먼저 해야 할 일은 SQLite 홈페이지에서 필요한 파일을 다운로드 받습니다.


다운로드 페이지에 가면 운영체제 별, 종류 별로 분류가 되어 있고 하단으로 조금 스크롤을 하면

Source Code 항목에 시간이 지나면 버전 정보는 달라 지겠지만 sqlite-amalgamation-xxxxxx.zip 형태의 소스파일을 다운 받습니다. 압축 파일을 풀면 헤더 파일과 소스 파일이 있습니다.


Precompiled Binaries for Windows 항목에는 윈도우용 파일이 있는데 소스파일과 동일한 버전인 sqlite-dll-xxxx.zip 형태를 가진 파일이 존재 합니다. 여기서 32-bit, 64-bit 중 자신의 시스템에 필요한 파일을 다운로드 받습니다.


MFC Sqlite



1.2. Lib 생성


다운 받은 파일은 적당한 곳에 압축을 풀어 주세요.

sqlite3.def

sqlite3.dll

두개의 파일만 보이고 우리가 사용할 lib 파일이 보이지 않는데 lib는 생성을 해야 합니다.


개발자 명령 프롬프트를 실행 합니다.  Visual Studio가 한글인지 영문인지에 따라 한글과 영문으로 나오지만 동일한 명령어 입니다.


MFC Sqlite


저는 한글이라 이렇게 나오고 영문이면 Developer Command Prompt 이렇게 되어 있습니다. 어찌되었건 실행을 하면 콘솔 창이 하나 나옵니다.


MFC Sqlite


Developer Command Prompt 콘솔 창이 나오면

압축을 푼 디렉토리로 이동을 하고 cd D:\sqlite-dll-win64-x64-3220000

lib 생성 명령을 입력 합니다.


32 bit : D:\sqlite-dll-win64-x64-3220000>LIB /DEF:sqlite3.def

64 bit : D:\sqlite-dll-win64-x64-3220000>LIB /DEF:sqlite3.def /machine:X64

이제 sqlite3.lib 파일이 생성 되었습니다.



2. MFC 프로젝트


2.1 프로젝트 생성


프로젝트를 하나 생성해서 sqlite를 활용해 보도록 하겠습니다.

MFC 프로젝트를 새로 하나 생성 합니다.

[단일 문서]를 설정 하는 것 이외에는 기본값으로 하고 계속 [다음]으로 넘어 갑니다.



최종단계에 도달 하면 간단한 이벤트를 사용하기 위해 [기본 클래스(A)] CFormView로 설정합니다.





2.2 설정


다운받은 source 파일 중에서 sqlite3.h 파일을 프로젝트 디렉토리로 옮기고 [기존 항목(G)]을 이용하여 추가 합니다.



생성된 Lib를 프로젝트에 추가합니다.

추가 방법은 프로젝트에 마우스를 대고 오른쪽을 눌러아신다고요. 안 손아파.



실행할떄 Dll을 찾는 경우도 있습니다. 실행위치에 복사해 줍니다.

실제 코딩을 위한 클래스를 추가해 줍니다.  파일 생성은 여기서는 DatabaseSql.cpp, DatabaseSql.h 이렇게 했습니다.



DB를 관리할 파일도 DatabaseSql.h, DatabaseSql.cpp 이렇게 두개 생성해 줍니다.

지금 생성한 4개 파일과 기존에 자동 생성된 MainFrm.h, MainFrm.cpp 두개의 파일만 코딩하면 작업이 완료 됩니다.


2.3 코딩


어떤 작업을 할건지 일단 그림을 한번 볼까요?

입력창을 4개 만들었는데 귀찮아서 앞에 있는 2개만 사용합니다.

물론 4개 다 DB에 저장을 하긴 하지만 입력하면 앞쪽 두개의 갑으로 프로젝트의 타이틀을 변경 시키는 프로그램을 만들라고 합니다.



- DatabaseSql 작업


DatabaseSql.h 에서는 쿼리 결과를 받아올 struct 생성하는 것만 보시고 나머지는 일반적인 설정들입니다. cpp 간단해서 첨부파일을 보시면 됩니다.


#include "stdafx.h"
#include "sqlite3.h"
#include 


typedef struct {
	char **pazResult;    /* Results of the query */
	int pnRow;           /* Number of result rows written here */
	int pnColumn;        /* Number of result columns written here */
	char *pzErrmsg;       /* Error msg written here */
}sqlite3_select, *sSelect;

class CDatabaseSql
{
public:
	CDatabaseSql();
	~CDatabaseSql();

	sqlite3 *pDbRef;
	char	*m_ErrMsg;

	int DatabaseOpen();  // DB 생성, 열기
	int ExecuteSqlite(CString sqlQuery);  //Insert, Update, Delete를 실행
	sqlite3_select SelectSqlite(CString sqlQuery); //select를 실행
	
	
};

- MainFrm 작업


sqlite Database 작업을 하기 MainFrm.h 파일에 다음 소스를 추가 합니다.

#include "DatabaseSql.h"

CDatabaseSql      m_DatabaseSql;

.

MainFrm.cpp 파일에 다음을 추가해서 프로그램이 실행될때 Database Table을 생성 하도록 다음 소스를 추가 합니다


int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
		//------------------------- CopyCoding Start ---------------------------------
	 
	// Create Database
	if (m_DatabaseSql.DatabaseOpen())
	{
		exit(-1);
	}
	// Create Table
	CString sql = _T("CREATE TABLE IF NOT EXISTS TB_SETTING(SEQ INTEGER PRIMARY KEY AUTOINCREMENT, SET1 TEXT, SET2 TEXT, SET3 TEXT); ");
	m_DatabaseSql.ExecuteSqlite(sql);
	
	//========================== CopyCoding ENd =================================
}

- SqliteTestView 작업


SqliteTestView.cpp에는 초기화시 DB 오픈하도록 해줍니다.


void CSqliteTestView::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();
	GetParentFrame()->RecalcLayout();
	ResizeParentToFit();

	// View에서 사용할 Database Open
	if (m_DatabaseSql.DatabaseOpen())
	{
		exit(-1);
	}
}

OnBnClickedBtnInput() 이 함수가 메인 작업입니다.

프로그램 흐름은 디비를 조회해서 자료가 있으면 읽어와서 타이틀을 변경 하고 입력한 값으로 변경합니다.  자료가 없으면 디비에 입력을 합니다.

프로그램을 하고 나니 기능을 한곳에 넣기 위해 어거지로 만든 기분이네요.


	GetDlgItemText(IDC_EDIT_VAL1, zTitle);
	GetDlgItemText(IDC_EDIT_VAL2, zVal1);
	GetDlgItemText(IDC_EDIT_VAL3, zVal2);
	GetDlgItemText(IDC_EDIT_VAL4, zVal3);
//입력란을 모두 적어줍니다.
	if (zTitle.IsEmpty() || zVal1.IsEmpty() || zVal2.IsEmpty() || zVal3.IsEmpty()) {
		MessageBox(_T("빈칸을 채워 주세요!"));
		return;
	}

	CString strSelQuery = _T("select * from TB_SETTING ;");  //쿼리 생성을 합니다.
	sqlite3_select p_selResult = m_DatabaseSql.SelectSqlite(strSelQuery); //조회 합니다.
	if (p_selResult.pnRow == 0) { //데이터가 없다고요?
		CString strInsQuery = _T("Insert into TB_SETTING VALUES( NULL,'" + zTitle + "','" + zVal1 + "','" + zVal2 + "','" + zVal3 + "');");  // 입력쿼리 생성해서
		int rc = m_DatabaseSql.ExecuteSqlite(strInsQuery);  //입력 해야죠
	}
	else {  //자료가 있네요. 아래에서 하나씩 읽어옵니다.
		for (int rowCtr = 0; rowCtr <= p_selResult.pnRow; ++rowCtr)
		{
			int colCtr = 0;
			int nCol = 1;
			int cellPosition = (rowCtr * p_selResult.pnColumn) + colCtr;

			std::string sel1 = p_selResult.pazResult[cellPosition++];
			CString zSeq(sel1.c_str());
			std::string sel2 = p_selResult.pazResult[cellPosition++];
			CString zTitle(sel2.c_str());
			std::string sel3 = p_selResult.pazResult[cellPosition++];
			CString zSet1(sel3.c_str());
			std::string sel4 = p_selResult.pazResult[cellPosition++];
			CString zSet2(sel4.c_str());
			std::string sel5 = p_selResult.pazResult[cellPosition++];
			CString zSet3(sel5.c_str());

			if (rowCtr == 0) {
				continue; //sqlite는 필드값도 가져와서 걸러줍니다.
			}

			SetValue(zTitle, zSet1);  //타이틀 변경 호출
		}

		CString strInsQuery = _T("Update TB_SETTING set TITLE='" + zTitle + "',SET1='" + zVal1 + "',SET2='" + zVal2 + "',SET3='" + zVal3 + "';"); //데이터가 존재하니 업데이트
		int rc = m_DatabaseSql.ExecuteSqlite(strInsQuery);
	}

3. 소스


Visual Studio 2017에서 생성했지만 2015에서도 작동되는걸 확인했습니다.

파일이 커서 소스들만 올리는데 실제 필요한건 앞에서도 설명드린 6개입니다.


SqliteTest.7z


res.7z


- copy coding -


자 그럼 TYPE_STEP_DETECTOR TYPE_STEP_COUNTER는 어떻게 차이가 나는지 동시에 테스트를 진행 하면서 확인해 보도록 하겠습니다.



1. TYPE_STEP_DETECTOR 와 TYPE_STEP_COUNTER의 차이점


TYPE_STEP_DETECTOR는 어떤 상황에서건 꿋꿋하게 항상 1만 리턴 합니다.

TYPE_STEP_COUNTER는 핸드폰을 켜고 센서를 작동했을 때부터의 총 횟수의 합을 리턴 합니다.

핸드폰을 재 시작 해야만 다시 0으로 초기화 됩니다.



1.1 TYPE_STEP_DETECTOR 리턴 값


TYPE_STEP_DETECTOR의 리턴 값을 찍어 보면 무조건 1만 리턴 합니다.


Step Detect : 0 (작동 전 return 값 없음)

Step Detect : 1 (return : 1.0)

Step Detect : 2 (return : 1.0)

어플리케이션 종료 / 시작

Step Detect : 0 (작동 전 return 값 없음)

Step Detect : 1 (return : 1.0)

핸드폰 재 시작

Step Detect : 0 (작동 전 return 값 없음)

Step Detect : 1 (return : 1.0)


1.2 TYPE_STEP_COUNTER 리턴 값


TYPE_STEP_COUNTER는 어플리케이션의 종료와 관계없이 계속 기존의 값을 가지고 있다가 1씩 증가한 값을 리턴 합니다. 

다시 0으로 초기화 하려면 핸드폰을 재 시작해야 합니다.


Step Count : 0 (작동 전 return 값 없음)

Step Count : 1 (return : 1.0)

Step Count : 2 (return : 2.0)

어플리케이션 종료 / 시작

Step Count : 3 (return : 3.0)

Step Count : 4 (return : 4.0)

핸드폰 재 시작

Step Count : 0 (작동 전 return 값 없음)

Step Count : 1 (return : 1.0)


아래 그림은 어플리케이션을 켜고 동시에 센서 측정을 시작한 결과와 어플리케이션을 종료 한 후 다시 시작 했을 때의 결과 입니다.


step detector counter

step detector counter


1.3 화면 종료 후 카운트


지금까지는 화면을 켜놓고 테스트를 하였습니다.

어플리케이션을 종료하지 않고 화면만 종료하고 테스트를 진행 하고 다시 화면을 켜면 숫자가 모두 그대로 입니다.

onPause() 이 함수에서 배터리를 아껴보겠다고 센서 작동을 중단 시켜서 입니다.


onPause() 함수를 중지 시킨 상태에서 화면을 끄고 테스트를 진행 하면 TYPE_STEP_DETECTOR TYPE_STEP_COUNTER 모두 증가 한 것을 볼 수 있습니다.


만보기를 만들려면 onPause() 함수는 삭제해야 하겠지요.


step detector counter


2. 프로그램 소스

 

2.1 신규 프로젝트 생성

프로젝트 명을 적당하게 명명해서 생성 하고 기타 설정 사항도 본인의 기호에 맞게 설정 하여 신규 프로젝트를 하나 생성 합니다.


2.2 Layout 작성

센서 작동에 대한 간단한 테스트만 진행 하기 때문에 센서에서 오는 값을 출력 할 수 있을 정도의 화면만 구성 합니다.


TextView를 하나 만들고 tvTitleid를 기입합니다. 

textandroid:text="Step Sensor" 이렇게 적어주고 이 값은 변경하지 않을 타이틀 값입니다.


    TYPE_STEP_DETECTORTYPE_STEP_COUNTER 센서로부터 받아온 값을 출력하기 위해 TextView 하나는 idtvStepDetector 라고 정의 하고 android:text="Step Detect : 0" 으로 초기 값을 적어 줍니다.


    다른 TextView 하나는 idtvStepCount 라고 정의 하고 android:text="Step Count : 0" 으로 초기 값을 적어 줍니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Step Sensor"
        android:layout_marginTop="50dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tvStepDetector"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Step Detect : 0"
        />
    <TextView
        android:id="@+id/tvStepCount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvStepDetector"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Step Count : 0"
        />
</android.support.constraint.ConstraintLayout>


2.3 MainActivity.java


1) class


센서로 부터의 값을 받아 올 수 있도록 classSensorEventListenerimplements 시켜 줍니다.


2) 변수 정의


프로그램 내에서 사용할 변수(센서, TextView, int)들을 정의 합니다.


3) onCreate()


변수에 값을 할당 하고 TYPE_STEP_DETECTOR, TYPE_STEP_COUNTER 센서가 핸드폰에 있는지 확인 합니다.

센서가 없으면 Toast를 이용해 화면에 잠시 메시지를 하단에 팝업으로 보여 줍니다.


4) onPause(), onResume()


Sensor는 다른 어플리케이션을 사용하기 위해 일시 중지 되거나 화면을 종료(turn off)해도 계속 작동하고 있으며 전력을 소모하고 있습니다.

이를 방지하기 위해서는 어플리케이션을 완전 종료하거나 다른 어플리케이션에 의해 일시 중지되는 경우 센서의 작동을 중지 시켜주고 이벤트를 받아 다시 센서관련 어플리케이션이 활성화 되었을 경우 작동이 되도록 하여야 합니다.

그러기 위해서 onPause()에서는 중지하고 onResume()에서는 활성화 하도록 코드를 추가 합니다.


5) onSensorChanged()


TYPE_STEP_DETECTOR는 이벤트로 받아온 값이 1.0f 이면 1씩 증가시켜 화면에 정의된 TextView에 값을 넘겨 주도록 합니다.

TYPE_STEP_COUNTER는 리턴 받은 값을 그대로 화면에 넘겨 줍니다.

package com.example.desk.stepdetectorcounter;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor stepDetectorSensor;
    TextView tvStepDetector;
    private int mStepDetector;

    private Sensor stepCountSensor;
    TextView tvStepCount;

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

        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        // DETECTOR
        tvStepDetector = (TextView)findViewById(R.id.tvStepDetector);
        stepDetectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
        if(stepDetectorSensor == null) {
            Toast.makeText(this, "No Step Detect Sensor", Toast.LENGTH_SHORT).show();
        }
        // COUNTER
        tvStepCount = (TextView)findViewById(R.id.tvStepCount);
        stepCountSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
        if(stepCountSensor == null) {
            Toast.makeText(this, "No Step Detect Sensor", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, stepDetectorSensor, SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(this, stepCountSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR) {
            if(event.values[0] == 1.0f) {
                mStepDetector += event.values[0];
                tvStepDetector.setText("Step Detect : " + String.valueOf(mStepDetector));
            }
        } else if(event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
            tvStepCount.setText("Step Count : " + String.valueOf(event.values[0]));
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
}



3. 결과

 

3.1 Source Code


첨부된 소스파일을 다운받아 적당한 곳에 압축을 풀고 Android Studio를 이용하여 File > Open 메뉴로 프로젝트 열고 실행을 합니다.

테스트를 위해서 Target Device는 개인 핸드폰으로 설정을 합니다.

각자 설치된 android studio 버전이 달라 update가 진행 되기도 하고 압축을 풀어놓은 디렉토리가 개발을 진행한 디렉토리 정보와 차이가 나서 오류가 발생 하기도 합니다.


만약 실행 중 팝업으로 오류가

Installation failed with message Invalid File: E:\android\app\build\intermediates\split-apk\debug\slices\slice_3.apk

이것 비스무리 하게 발생한다면 Android Studio 상단 Build 메뉴 에서

Build > Clean Project

Build > Rebuild Project

메뉴를 이용하여 기존 Build 정보를 삭제 하고 다시 실행 하면 될 것 입니다.

 

 

StepDetectorCounter.7z



3.2 APK File

Android Studio가 없거나 귀찮아 첨부된 APK 파일을 이용하여 핸드폰에서 실행을 하려면 출처를 알 수 없은 앱 설치를 가능하게 하고 실행을 해야 합니다. 

테스트 후에는 다시 출처를 알 수 없는 앱 설치 가능을 차단 해 줍니다.

어디서 설정을 변경 했는지 모르겠다 싶으면 핸드폰에 있는 은행 앱을 하나 실행 하면 출처를 알 수 없는 앱 설치 설정 기능을 차단하라고 메시지가 나오면서 변경할 수 있는 위치로 이동할 수 있도록 되어 있으니 바꿔주면 됩니다.

 

stepDetectCount.apk


- copy coding -


TYPE_STEP_COUNTER 센서는 TYPE_STEP_DETECTOR 센서와 작동 방법이 동일 하고 리턴 값만 차이가 나기 때문에

TYPE_STEP_DETECTOR 센서 내용을 복사 해서 대충 적어 봅니다..

우리가 흔히 만보기 어플리케이션을 만들 때 사용하는 센서로 걸어가는 동작을 하였는지 감지하며
발을 내디뎌 땅에 닫는 순간 리턴 값을 보내 주는 센서 입니다.



1. Sensor event data


1.1 걸음 감지 센서 이벤트 값


센서가 작동되면 움직임을 감지 하고 있다가 걷기 동작이 진행 되면 감지될 때마다 1씩 증가된 최종 값을  리턴 받아 올 수 있습니다.


TYPE_STEP_DETECTOR 센서와 달리 걷기 동작을 감지하여 계속 덧셈을 하고 있기 때문에 이 센서를 사용하여

만보기를 만든다면 최종 값만 보여주면 됩니다.


1.2 걸음 수 측정 센서 이벤트 값


Sensor

 Sensor event data

 표현 값

 측정 단위

 TYPE_STEP_COUNTER

 SensorEvent.values[0]

 핸드폰이 다시시작(reboot) 된 이후 부터의 걸음 수

 걸음 수


1.3 센서의 이벤트 비율(rate)


센서로부터 얼마나 자주 값을 받을 것인가에 대한 설정은 registerListener() 메소드를 이용하여 설정 합니다


- SENSOR_DELAY_NORMAL : 200,000 microsecond delay

- SENSOR_DELAY_UI : 60,000 microsecond delay

- SENSOR_DELAY_GAME : 20,000 microsecond delay

- SENSOR_DELAY_FASTEST : 0 microsecond delay



2. 걸음 감지 센서 프로그램

 

2.1 신규 프로젝트 생성


프로젝트 명을 적당하게 명명해서 생성 하고 기타 설정 사항도 본인의 기호에 맞게 설정 하여 신규 프로젝트를 하나 생성 합니다.


2.2 Layout 작성


센서 작동에 대한 간단한 테스트만 진행 하기 때문에 센서에서 오는 값을 출력 할 수 있을 정도의 화면만 구성 합니다.


어플리케이션을 작동 시켰을 때 초기 화면에 보여주는 값들 입니다.


- TextView를 하나 만들고 idtvTitle로 정의합니다. 

  textandroid:text="Step Counter Sensor" 이렇게 적어주고 이 값은 변경하지 않을 값입니다.


- TextView를 하나 더 생성 하고 idtvStepCounter 라고 정의해 둡니다.

  TYPE_STEP_COUNTER Sensor 센서로부터 받아온 값을 출력할 때 사용 할 용도 이며

   textandroid:text="Step Count : 0" 으로 초기 값을 일단 적어 줍니다.


- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Step Counter Sensor"
        android:layout_marginTop="50dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tvStepCount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        android:text="Step Count : 0"
        />
</android.support.constraint.ConstraintLayout>


2.3 MainActivity.java


1) class implement


센서로 부터의 값을 받아 올 수 있도록 classSensorEventListenerimplements 시켜 줍니다.

onSensorChanged()onAccuracyChanged() 함수를 override 할 수 있습니다.


2) 변수 정의


프로그램 내에서 사용할 변수(SensorManager, Sensor, TextView, int)들을 정의 합니다.


3) onCreate()


설정한 변수들에 값을 할당 하고 TYPE_STEP_COUNTER 센서가 핸드폰에 있는지 확인 합니다.

센서가 없으면 Toast를 이용해 화면에 잠시 메시지를 하단에 팝업으로 보여 줍니다.


4) onPause(), onResume()


Sensor는 다른 어플리케이션을 사용하기 위해 일시 중지 되거나 화면을 종료(turn off)해도 계속 작동하고 있으며 전력을 소모하고 있습니다.


이를 방지하기 위해서는 어플리케이션을 완전 종료하거나 다른 어플리케이션에 의해 일시 중지되는 경우 센서의 작동을 중지 시켜주고

이벤트를 받아 다시 센서관련 어플리케이션이 활성화 되었을 경우 작동이 되도록 하여야 합니다.


그러기 위해서 onPause()에서는 중지하고 onResume()에서는 활성화 하도록 코드를 추가 합니다.


5) onSensorChanged()


실제 센서의 작동과 관련된 함수입니다. 센서는 동작을 감지 하면 이벤트를 발생하여onSensorChanged 함수에 값을 전달 합니다.


이벤트가 발생하여 함수에 전달되는 값은 걸음을 걸을 때마다 1씩 증가된 최종 값으로 화면에 정의된 TextView에 값을 넘겨 주도록 합니다.

어플리케이션을 실행해 보면 카운트가 1씩 증가하는걸 볼 수 있습니다.


- MainActivity.java


package com.example.desk.stepcounter;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor stepCountSensor;
    TextView tvStepCount;

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

        tvStepCount = (TextView)findViewById(R.id.tvStepCount);
        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        stepCountSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
        if(stepCountSensor == null) {
            Toast.makeText(this, "No Step Detect Sensor", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, stepCountSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
            tvStepCount.setText("Step Count : " + String.valueOf(event.values[0]));
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

}



3. 결과


3.1 결과 화면


프로젝트를 가상 디바이스가 아닌 실제 핸드폰에서 실행하고 잠시 걸어 다니면서 테스트한 결과 아래와 같은 화면이 나옵니다.

어플리케이션을 종료한 후 다시 시작하면 값이 초기화 되어 Step Count : 0 으로 되며 다시 1씩 증가하게 됩니다.


step counter android sensor



3.2 Source Code


첨부된 소스파일을 다운받아 적당한 곳에 압축을 풀고 Android Studio를 이용하여 File > Open 메뉴로 프로젝트 열고 실행을 합니다.


테스트를 위해서 Target Device는 개인 핸드폰으로 설정을 합니다.


각자 설치된 android studio 버전의 차이와 lib들에 차이가 있어 어플리케이션을 Run 하면 update가 필요 하기도 하고 압축을 풀어놓은

디렉토리가 제가 개발을 진행한 디렉토리 정보와 차이가 나서 오류가 발생 하기도 합니다.


업데이트는 잠시 기다리며 finish를 기다려 줍니다.


만약 실행 중 팝업으로 오류가

Installation failed with message Invalid File: E:\android\app\build\intermediates\split-apk\debug\slices\slice_3.apk

이것 비스무리 하게 발생한다면 Android Studio 상단 Build 메뉴 에서


Build > Clean Project

Build > Rebuild Project


메뉴를 이용하여 기존 Build 정보를 삭제 하고 다시 실행 하면 될 것 입니다.


StepCounter.7z



3.3 APK File

Android Studio가 없거나 설치가 귀찮으면 첨부된 APK 파일을 이용하여 핸드폰에서 실행해도 됩니다.


처음 설치를 하려고 하면 출처를 알 수 없은 앱을 굳이 설치 하려고 하느냐고 물어보는데 그럴꺼라고 설정을 해야 설치됩니다. 

테스트 후에는 다시 출처를 알 수 없는 앱 설치 가능을 차단 해 줍니다.

어디서 설정을 변경 했는지 모르겠다 싶으면 핸드폰에 있는 은행 앱을 하나 실행해 봅니다.

그러면 출처를 알 수 없는 앱 설치 설정 기능을 차단하라고 메시지가 나오면서 변경할 수 있는 위치로 이동할 수 있도록 되어 있으니 바꿔주면 됩니다.


setpCount.apk


- copy coding -


우리가 흔히 만보기 어플리케이션을 만들 때 사용하는 센서로 걸어가는 동작을 하였는지 감지하며 발을 내디뎌 땅에 닫는 순간 리턴 값을 보내 주는 센서 입니다.



1. Sensor event data


1.1 걸음 감지 센서 이벤트 값


센서가 작동되면 움직임을 감지 하고 있다가 걷기 동작이 진행 되면 감지될 때마다 동일 하게 1.0의 리턴 값을 받아 올 수 있습니다.

걷기 동작의 감지 유무만 확인하여 매번 동일한 값을 보내주기 때문에 이 센서를 사용하여 만보기를 만든다면 계속 덧셈을 해줘야 하는 작업이 필요 합니다.  그리고 덧셈한 최종 값은 어디엔가 저장을 해야 하겠죠.



1.2 센서의 이벤트 비율(rate)


센서로부터 얼마나 자주 값을 받을 것인가에 대한 설정은 registerListener() 메소드를 이용하여 설정 합니다.

- SENSOR_DELAY_NORMAL : 200,000 microsecond delay

- SENSOR_DELAY_UI : 60,000 microsecond delay

- SENSOR_DELAY_GAME : 20,000 microsecond delay

- SENSOR_DELAY_FASTEST : 0 microsecond delay



2. 걸음 감지 센서 프로그램



2.1 신규 프로젝트 생성


프로젝트 명을 적당하게 명명해서 생성 하고 기타 설정 사항도 본인의 기호에 맞게 설정 하여 신규 프로젝트를 하나 생성 합니다.



2.2 Layout 작성


센서 작동에 대한 간단한 테스트만 진행 하기 때문에 센서에서 오는 값을 출력 할 수 있을 정도의 화면만 구성 합니다.

어플리케이션을 작동 시켰을 때 초기 화면에 보여주는 값들 입니다.


- TextView를 하나 만들고 idtvTitle로 정의합니다. 

   textandroid:text="Step Detector Sensor" 이렇게 적어주고 이 값은 변경하지 않을 값입니다.


- TextView를 하나 더 생성 하고 idtvStepDetector 라고 정의해 둡니다.

   TYPE_STEP_DETECTOR Sensor 센서로부터 받아온 값을 출력할 때 사용 할 용도 이며

   textandroid:text="Step Detect : 0" 으로 초기 값을 일단 적어 줍니다.


- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Step Detector Sensor"
        android:layout_marginTop="50dp"
        android:textSize="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tvStepDetector"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Step Detect : 0"
        app:layout_constraintTop_toBottomOf="@+id/tvTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:textSize="25dp"
        />
</android.support.constraint.ConstraintLayout>


2.3 MainActivity.java


1) class implement


센서로 부터의 값을 받아 올 수 있도록 classSensorEventListenerimplements 시켜 줍니다.

onSensorChanged()onAccuracyChanged() 함수를 override 할 수 있습니다.


2) 변수 정의


프로그램 내에서 사용할 변수(SensorManager, Sensor, TextView, int)들을 정의 합니다.


3) onCreate()


설정한 변수들에 값을 할당 하고 TYPE_STEP_DETECTOR 센서가 핸드폰에 있는지 확인 합니다.

센서가 없으면 Toast를 이용해 화면에 잠시 메시지를 하단에 팝업으로 보여 줍니다.


4) onPause(), onResume()


Sensor는 다른 어플리케이션을 사용하기 위해 일시 중지 되거나 화면을 종료(turn off)해도 계속 작동하고 있으며 전력을 소모하고 있습니다.


이를 방지하기 위해서는 어플리케이션을 완전 종료하거나 다른 어플리케이션에 의해 일시 중지되는 경우 센서의 작동을 중지 시켜주고 이벤트를 받아 다시 센서관련 어플리케이션이 활성화 되었을 경우 작동이 되도록 하여야 합니다.


그러기 위해서 onPause()에서는 중지하고 onResume()에서는 활성화 하도록 코드를 추가 합니다.


5) onSensorChanged()


실제 센서의 작동과 관련된 함수입니다. 센서는 동작을 감지 하면 이벤트를 발생하여onSensorChanged 함수에 값을 전달 합니다.

이벤트가 발생하여 함수에 전달한 값은 1.0 입니다. 

이 값을 이용하여 변수를 1씩 증가시켜 화면에 정의된 TextView에 값을 넘겨 주도록 합니다.

어플리케이션을 실행해 보면 카운트가 1씩 증가하는걸 볼 수 있습니다.


public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private SensorManager sensorManager;
    private Sensor stepDetectorSensor;
    TextView tvStepDetector;
    private int mStepDetector;

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

        tvStepDetector = (TextView)findViewById(R.id.tvStepDetector);
        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        stepDetectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
        if(stepDetectorSensor == null) {
            Toast.makeText(this, "No Step Detect Sensor", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, stepDetectorSensor, SensorManager.SENSOR_DELAY_UI);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR) {
            if(event.values[0] == 1.0f) {
                mStepDetector++;
                tvStepDetector.setText("Step Detect : " + String.valueOf(mStepDetector));
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

}



3. 결과


3.1 결과 화면


프로젝트를 가상 디바이스가 아닌 실제 핸드폰에서 실행하고 잠시 걸어 다니면서 테스트한 결과 아래와 같은 화면이 나옵니다.


어플리케이션을 종료한 후 다시 시작하면 값이 초기화 되어 Step Detect : 0 으로 되며 다시 1씩 증가하게 됩니다.




3.2 Source Code


첨부된 소스파일을 다운받아 적당한 곳에 압축을 풀고 Android Studio를 이용하여 File > Open 메뉴로 프로젝트 열고 실행을 합니다.


테스트를 위해서 Target Device는 개인 핸드폰으로 설정을 합니다.


각자 설치된 android studio 버전의 차이와 lib들에 차이가 있어 어플리케이션을 Run 하면 update가 필요 하기도 하고 압축을 풀어놓은 디렉토리가 제가 개발을 진행한 디렉토리 정보와 차이가 나서 오류가 발생 하기도 합니다.


업데이트는 잠시 기다리며 finish를 기다려 줍니다.


만약 실행 중 팝업으로 오류가


Installation failed with message Invalid File: E:\android\app\build\intermediates\split-apk\debug\slices\slice_3.apk


이것 비스무리 하게 발생한다면 Android Studio 상단 Build 메뉴 에서


Build > Clean Project

Build > Rebuild Project


메뉴를 이용하여 기존 Build 정보를 삭제 하고 다시 실행 하면 될 것 입니다.


StepDetector.7z



3.3 APK File


Android Studio가 없거나 설치가 귀찮으면 첨부된 APK 파일을 이용하여 핸드폰에서 실행해도 됩니다.

처음 설치를 하려고 하면 출처를 알 수 없은 앱을 굳이 설치 하려고 하느냐고 물어보는데 그럴꺼라고 설정을 해야 설치됩니다. 

테스트 후에는 다시 출처를 알 수 없는 앱 설치 가능을 차단 해 줍니다.

어디서 설정을 변경 했는지 모르겠다 싶으면 핸드폰에 있는 은행 앱을 하나 실행해 봅니다.

그러면 출처를 알 수 없는 앱 설치 설정 기능을 차단하라고 메시지가 나오면서 변경할 수 있는 위치로 이동할 수 있도록 되어 있으니 바꿔주면 됩니다.


프로그램 보다 헛소리가 더긴 글이넹


stepDetector.apk


- copy coding -


1···114115116117118

+ Recent posts