-
마스크 구매 알림이 개발기 - 3안드로이드 2020. 3. 13. 13:29
UI 작업까지 완성되었다. 그래도 뭔가 2프로 부족한 느낌..
생각해보면 어떻게 사용자가 매번 들어와 새로고침 버튼을 눌러서 마스크 재고가 있는지 확인할까?
그래서 백그라운드 서비스에서 주기적으로 재고 확인을 하는 기능도 추가하기로 했다.
서비스 만드는건 크게 어렵지 않았다.
안드로이드 매니페스트에 아래와 같이 서비스 클래스를 정의해주고,
<service android:name="ParsingService"></service>
해당 클래스에서 Service 클래스를 extend 해주면 그 클래스는 서비스로 등록이 된다.
다른 액티비티들처럼 onCreate나 onBind 등의 이벤트 처리를 해줄 수도 있다.
서비스 내부에서 타이머를 이용해 주기적으로 실행할 작업을 처리한다.
Timer timer = new Timer(); TimerTask TT = new TimerTask() { @Override public void run() { try { parse_count = parsePage.size(); isMaskEnable = false; for (int i = 0; i < parse_count; i++) { final int tempint = i; Document doc = Jsoup.connect(parsePage.get(i)).get(); ///// 구매하기 버튼 찾기 Element buybtn = doc.select("a[title=구매하기]").first(); if (buybtn != null) { String buyEnable = buybtn.attr("class"); isMaskEnable = buyEnable.contains("_buy_button _click"); ///// 구매가 가능하다면 if (isMaskEnable) { final String finalUrl = parsePage.get(i); Handler mHandler = new Handler(Looper.getMainLooper()); mHandler.postDelayed(new Runnable() { @Override public void run() { ///// 상태바에 Notification을 띄운다 makeNotification(finalUrl, tempint); } }, 0); } } } if(!isMaskEnable){ for(int i = 0; i<parse_count; i++){ ///// 이건 한 제품이 구매가 가능하면 구매 불가능할때까지 알림이 계속 오는 것을 방지하고자 넣었다. ///// 알람을 띄우면 1, 띄운적이 없으면 0 checkRenoti[i] = 0; } } } catch (IOException e){ } } }; ///// 5초마다 한번씩 실행 timer.schedule(TT, 0, 5000);
이걸 눈치챘는지 모르겠지만 사실 1, 2편에서와 달라진 점이 하나 있다.
앞에서는 파싱할 URL 리스트를 Array에 저장했었지만, ArrayList 형식으로 변경했다.
마스크 구매 페이지 URL이 추가되기도 하고 변경되기도 한다는 점을 깨닫고 URL 리스트가 주기적으로 업데이트가 필요하다 판단했고, 마스크 판매 페이지 URL을 기록하는 HTML을 만들어 개인 서버에 업로드하고 해당 페이지를 파싱해 URL 리스트를 가져오는 식으로 개발했다.
이러면 URL 리스트가 업데이트 될때마다 앱을 배포하지 않아도 되고 리스트 업데이트도 수월했다.
하지만 Array 방식의 URL 리스트에서는 요소의 추가 및 삭제가 쉽지 않아 ArrayList 방식을 사용하기로 결정했다.
그건 그렇고, 서비스가 완성되서 진짜 끝난줄 알았다. 그런데 시간이 좀 지나니 서비스가 동작하지 않는것을 볼 수 있었다.
아니 이게 무슨일이야안드로이드 OS 내부에서 메모리 관리를 위해 앱 화면이 Foreground에 있지 않으면 프로세스를 종료한다고 한다.
포기하긴 이르다. 생각해보면 카카오톡은 계속 실행이 되고있다. 분명 뭔가 방법이 있을거라 생각하고 찾아보니!
포그라운드 서비스를 사용하면 사용자가 강제종료하지 않는 이상 지속적으로 서비스가 돌아가게 만들 수 있었다.
기본 서비스와 다른점은 상태바에 서비스가 동작중이라는 알림이 뜬다는 점이다.
사용자에게 조금 불편할 수도 있겠지만 지속적으로 구동되게 할 수 있어 그 방식을 사용하기로 했다.
void startForegroundService() { Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); ///// 사용자에게 보여질 알림창 생성 NotificationCompat.Builder builder; if (Build.VERSION.SDK_INT >= 26) { String CHANNEL_ID = "snwodeer_service_channel"; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "SnowDeer Service Channel", NotificationManager.IMPORTANCE_DEFAULT); ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)) .createNotificationChannel(channel); builder = new NotificationCompat.Builder(this, CHANNEL_ID); } else { builder = new NotificationCompat.Builder(this); } builder.setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("마스크 구매 가능여부 실시간 확인중") .setContentIntent(pendingIntent); ///// 포그라운드로 서비스 실행 startForeground(1000, builder.build()); }
만드는건 정말 어렵지 않다.
일반 Notification 알람을 만드는 것 처럼 buider를 이용해 알림창을 생성하고 해당 빌더와 함께 startForeground 메소드를 호출하면 된다. 그럼 아래 사진과 같이 알림창이 뜨고 서비스가 꺼지지 않는다.
이렇게 어느정도 구현할 때 중요했던 부분들은 다 복기해본 것 같다. 힘들기도 했지만 재밌게 개발하며 많이 배울 수 있었던 프로젝트였다.
'안드로이드' 카테고리의 다른 글
Android Exoplayer 플레이리스트 (0) 2020.03.17 Android Exoplayer UI 커스터마이징 (0) 2020.03.16 마스크 구매 알림이 개발기 - 2 (0) 2020.03.11 마스크 구매 알림이 개발기 - 1 (0) 2020.03.11 안드로이드 32bit 기기에서 2GB 이상 파일 다루기 (0) 2019.12.12 댓글