일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 병럴프로그래밍
- 책
- kotlin강좌
- mockito
- 코틀린
- ReactiveProgramming
- k8s
- Rxjava
- g 단위테스트
- android
- 회고
- 글또
- Kotlin
- Coroutine
- 안드로이드강좌
- 병렬프로그래밍
- 안드로이드
- 코루틴
- Compose
- 알고리즘
- 알게되는
- 자바
- 테스트
- theming
- viewmodel
- 스레드
- Gradle
- 커스텀상태
- 디자인패턴
- 안드로이드스튜디오
- Today
- Total
선생님, 개발을 잘하고 싶어요.
안드로이드 - 죽지않는 블루투스 스캐닝 본문
항상 블루투스를 스캐닝 하는 어플리케이션을 만들 일이 생겼다.
필요한 사항으론
1. 블루투스를 "항상" 스캐닝 한다.
2. 특정 블루투스가 감지되는지 안되는지 여부를 판단해 lost / found를 설정한다.
이를 위해 프로그램 개발 방향은
0. 블루투스 권한 및 위치 권한 확보
1. "항상" 스캐닝 할 수 있도록 service 를 구성한다.
2. service 가 꺼지지 않도록 한다.
3. lost / found 상태를 타이머를 통해 설정한다.
0.
메니페스트에 권한 설정을 해주고
1 2 3 | <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> | cs |
onCreate 시에 블루투스 확인과 위치권한 확인을 동적으로 수행해주자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | final BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } // Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION)) { // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1234); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. } } | cs |
1 - 2.
서비스 클래스를 만들고, onStartCommand 에 다음과 같이 service를 foreground 로 실행시켜준다. (foreground 로 실행하면 서비스가 강제 task killer에 의해 강제종료 되지 않는다.)
1 2 3 | public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { startForeground(1, new Notification()); | cs |
3.
스캔을 쭉 받다가 found / ready 상태일때 일정시간 동안 스캔이 없으면 lost 감지한다. lost 상태에서 스캔을 받게되면 found 상태로 변경 시킨다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | private BluetoothAdapter.LeScanCallback mLeScanCallbackWithTimer = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { if (device.getAddress().equals(mTargetAddress)) { if (mScanState == 0 || mScanState == 1) { // 발견하면 didFoundBeacon(); } // 타이머를 끄고 if (mMissingTimerTask != null) { mScanMissing = 0; mMissingTimerTask.cancel(); } mMissingTimerTask = createMissingTimerTask(); // 타이머를 킨다. mMissingTimer.schedule(mMissingTimerTask, MISSING_PERIOD); } } }; private TimerTask createMissingTimerTask() { return new TimerTask() { @Override public void run() { mScanMissing++; addLogText(mScanMissing + " missing !"); if (mScanMissing == mScanDepth) { // 잃어버림 didLostBeacon(); } else { // 스캔을 다시시작 scanLeDeviceWithTimer(false); mMissingTimerTask.cancel(); mMissingTimerTask = createMissingTimerTask(); mMissingTimer.schedule(mMissingTimerTask, MISSING_PERIOD); scanLeDeviceWithTimer(true); } } }; } | cs |
mScanDepth 횟수 만큼 재시도를 하고, 그럼에도 실패했다면 lost 처리 한다.
해당 스캔이 발견될 당시 lost 나 ready 상태였다면 바로 found 처리를 해서 found 는 신호가 오는 즉시 발동하도록 하였다.
15번 줄에 TimerTask를 새로 만들어 준 부분은 타이머 cancel 하고 해당 객체를 사용해 다시 타이머를 등록하는게 불가능하더라; 그래서 멤버변수로 쓰려고 했던 MissingTimerTask를 그냥 TimerTask를 생성하는 함수로 만들고 항상 새로운 객체를 스케쥴링 하도록 제작 하였다.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
안드로이드 9 부터 위의 권한도 설정해주어야 한다. 다들 설정하자.
'개발 > android 개발' 카테고리의 다른 글
코틀린 데이터바인딩 연결시 (kotlin databinding) (0) | 2018.11.27 |
---|---|
androidx navigation 구현해보자 (0) | 2018.11.23 |
잠금화면 어플리케이션(ProjectM) 개발 초기 개발리스트 (0) | 2018.11.20 |
안드로이드 통화 상태 감지 코드 (0) | 2018.11.20 |
안드로이드 서비스 정리 (0) | 2018.10.03 |