[재난알림앱Beacon6] workmanager와 끝나지 않는 오류들

Boknami·2023년 8월 16일
0

프로젝트_비콘

목록 보기
6/10

📚 workmanager?

일단 workmanager를 공부하기 시작하게 된 계기는
비회원이 자신의 위치를 서버로 보내기 위해서는

  1. 어플을 굳이 키고 있지 않더라도
  2. 어플이 종료되더라도
  3. 클라이언트의 화면이 꺼져있더라도

정상적으로 코드를 주기적으로 작동시킬 수 있어야 하기 때문이다.
이 모든 것을 만족하는 것이 workmanager였다.

지금까지 백그라운드 + 앱이 종료되더라도 실행하기 위해서는
이 전에는 Service + 포그라운드 서비스를 이용해서라도 가능한 것 같다. 비록 상단바에 앱이 추적되고 있는? 상태가 된다고 하는 것 같지만.
아 그리고 API 29? 버전부터는 이러한 조합을 이용하여 구현한 앱은 정식앱 등록이 안된다라는 부분도 본 것 같다.

하지만 여러가지 찾아봤을 때 가장 큰 문제는 안드로이드의 버전이 상승하면서 이러한 부분들이 점점 제약이 되거나 변했다. 백그라운드에서 계속 무언가 서비스를 한다는 것은 당연하게도 지속적으로 클라이언트의 배터리 사용량을 증가시키는 또 클라이언트의 자원을 사용해야하는 경우이다. 이에 대해 안드로이드에서는 workmanager를 통해서 이러한 것들을 관리하기를 원하는 것 같았다.

만약 니가
1. 어플을 굳이 키고 있지 않더라도
2. 어플이 종료되더라도
3. 클라이언트의 화면이 꺼져있더라도

를 찾는다면 workmanager를 사용해..근데 적절한 주기를 맞춰서..이런 느낌이였다.

계속 워크매니저에 대해서 공부하고 있지만 아직 100% 이해하지 못했다. 계속 하면서 더 학습을 해야한다.

🤣 workmanager이슈는 언제 닫을 수 있나..

지금까지 14일째 workmanager을 테스트하고 있다.
아직도 해당 이슈는 close하지 못하고 있다.

현재의 가장 큰 문제는 workmanager가 동작은 하나..정확한 주기에 맞게 실행이 안되는 부분이다.

💡 workmanager에 주의점

이 전의 엄청나게 많은 테스트가 있었다. 몇 번을 테스트 한 지 모르겠다.
이번 주 회의에서 알게 된 것은 팀원분 중 한 분이 말씀 주시기로 workmanager를 성공적으로 구현하신 분께서 간격이 너무 짧으면 workmanager가 정상적으로 실행되지 않을 확률이 높다는 것이었다. 나는 지금까지 테스트를 10초 간격으로 진행했으니 제대로 이것이 실행될 확률이 만무했다..

이 전의 코드

val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build()

    val workRequest = PeriodicWorkRequest.Builder(
        LocationUploadWorker::class.java,
        10, TimeUnit.SECONDS // 10초 간격으로 설정
    )
        .setConstraints(constraints)
        .build()

    WorkManager.getInstance(context).enqueue(workRequest)

😐 workmanager 테스트

해당 코드는 15분을 주기로 위치를 체크하고 알림을 띄우는 클래스를 실행하는 코드다
물론 위치를 찾기 위해서는 네트워크가 필요하기에 제약에 네트워크 설정에 대한 제약을 담았고,
15분을 주기로 하기 위한 부분도 repeatinterval에 적용했다.

그런데..실제 기기에 이 코드를 넣고 진행했을 때 이상하게도 3분마다 또는 2분마다 실행이 되었다. 도데체 왜 그럴까.


이번에는 7분만에 실행되었는데 갑자기 한 번에 막 실행이 된다.
workmanager자체가 작업을 큐에 넣고 실행하는 것은 알기에 연기된 것을 한 번에 처리한다? 라고 생각하면 이 일 자체가 이해는 된다.
그런데 애초에 주기가 15분이고 지체되지도 않았는데 이런식으로 작동하는 이유는 뭘까.

😵 왜 workmanager는 주기를 지키지 않는가

시도1)권한을 넣어보자

사실 workmanager는 크게 권한이 필요하지 않는다.
앱에서 위치 같은 부분에 대해서의 권한을 요하기 때문에 그 부분에 대한 권한을 앱에서 요구하는 것이지 workmanager가 이런 부분이 필요하단 부분은 없다. 그러나 혹시나..혹시나 하는 마음에서 해봤지만 역시 실패 온갖 권한을 요청했지만 의미없다.

// Location and Network permission check
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
            || ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
            || ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED) {

            val permissions = arrayOf(
                android.Manifest.permission.ACCESS_FINE_LOCATION,
                android.Manifest.permission.ACCESS_COARSE_LOCATION,
                android.Manifest.permission.ACCESS_NETWORK_STATE
            )

            val storagePermissions = arrayOf(
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            )

            if (ContextCompat.checkSelfPermission(this, storagePermissions[0]) != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(this, storagePermissions[1]) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, storagePermissions, STORAGE_PERMISSION_REQUEST_CODE)
            }

            ActivityCompat.requestPermissions(this, permissions, MY_PERMISSION_ACCESS_ALL)
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // Request ignore battery optimizations
            val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
            intent.data = Uri.parse("package:$packageName")
            startActivity(intent)
        }

시도2)버전을 바꿔보자

현 버전 : 2.7.0
변경 버전 : 2.8.0

시도3)제약 조건을 걸지 말아보자.

class StartApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Log.d("테스트", "앱이 시작되었습니다")
        //<--------------workmanager test-------------->
//        val constraints = Constraints.Builder()
//            .setRequiredNetworkType(NetworkType.CONNECTED)
//            .build()

        val workRequest = PeriodicWorkRequest.Builder(
            LocationNotificationWorker::class.java, 15, TimeUnit.MINUTES
        )
                //백오프 => WorkManager가 실패한 작업 요청 재시도를 처리하는 방법
            //.setBackoffCriteria(
            //    BackoffPolicy.LINEAR,
            //    PeriodicWorkRequest.MIN_BACKOFF_MILLIS,
            //    TimeUnit.MILLISECONDS
            // )
           // .setConstraints(constraints)
            .build()

        WorkManager.getInstance(this).enqueue(workRequest)
    }
}

제약 조건을 설정하는 val constraints을 아예 주석처리를 하고 돌려봤다.

이것도 큰 의미가 없다..

시도4 : 성공

성공했다..정확히 15분을 주기로 정상적으로 작동중이다..
원인은 내 테스트용 기기가 문제였던 것 같다..혹은 안드로이드의 버전
현재 테스트 기기에도 정상적으로 작동할 수 있도록 API수정을 하든지 해봐야겠다.


실제 기기에서도 성공했다..진짜 너무 힘들었다 워크매니저 하나가 나한테 너무나 큰 고통을 주었다..별에 별 걸 다 해보다가 어플 자체 설정에 들어가서 백그라운드 작업에 대한 제약을 아예 없게 만들어주니 정상적으로 작동을 한다..백그라운드 데이터를 먹는 부분을 코드적으로 해결을 해봐야겠다.

=> 화이트리스트에 등록하는 형식으로 진행해야할 것 같다.

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
    PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
    if (powerManager.isIgnoringBatteryOptimizations(getPackageName()) == false) {
        Intent intent = new Intent();
        intent.intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
        startActivity(intent);
    }
}

참고한 블로그 : https://parkho79.tistory.com/106

0개의 댓글