애플리케이션이 빠르고 반응성이 뛰어나더라도 특정 설계 결정으로 인해 다른 애플리케이션이나 대화상자와의 예기치 않은 상호작용, 의도치 않은 데이터 손실, 의도하지 않은 차단 등으로 인해 사용자에게 문제가 발생할 수 있습니다. 이러한 문제를 방지하려면 애플리케이션이 실행되는 컨텍스트와 애플리케이션에 영향을 줄 수 있는 시스템 상호작용을 이해하면 도움이 됩니다. 간단히 말해 시스템 및 다른 애플리케이션과 원활하게 상호작용하는 애플리케이션을 개발해야 합니다.
일반적인 원활함 문제는 서비스 또는 broadcast receiver와 같은 애플리케이션의 백그라운드 프로세스가 특정 이벤트에 대한 응답으로 대화상자를 표시하는 경우입니다. 특히 에뮬레이터에서 애플리케이션을 독립적으로 빌드하고 테스트할 때 무해한 동작으로 보일 수 있습니다. 그러나 애플리케이션이 실제 기기에서 실행되는 경우 백그라운드 프로세스가 대화상자를 표시할 때 사용자 포커스가 애플리케이션에 없을 수 있습니다. 따라서 애플리케이션이 활성 애플리케이션 뒤에 대화상자를 표시하거나 현재 애플리케이션에서 포커스를 가져와 사용자가 하고 있는 작업 (예: 전화 걸기) 앞에 대화상자를 표시할 수 있습니다. 이 동작은 애플리케이션이나 사용자에게 작동하지 않습니다.
이러한 문제를 방지하려면 애플리케이션에서 사용자에게 알리는 데 적절한 시스템 기능인 Notification
클래스를 사용해야 합니다. 알림을 사용하면 애플리케이션에서 포커스를 맞추고 사용자를 방해하지 않고 상태 표시줄에 아이콘을 표시하여 이벤트가 발생했음을 사용자에게 알릴 수 있습니다.
원활함 문제의 또 다른 예는 활동이 onPause() 및 기타 수명 주기 메서드를 올바르게 구현하지 않아 실수로 상태 또는 사용자 데이터를 손실하는 것입니다. 또는 애플리케이션이 다른 애플리케이션에서 사용할 데이터를 노출하는 경우, 예를 들어 누구나 읽을 수 있는 원시 파일이나 데이터베이스를 통해 노출하지 말고 ContentProvider를 통해 노출해야 합니다.
이러한 예의 공통점은 시스템 및 기타 애플리케이션과 원활하게 협력해야 한다는 점입니다. Android 시스템은 애플리케이션을 블랙박스 코드 청크가 아니라 느슨하게 결합된 구성요소의 일종의 연합으로 처리하도록 설계되었습니다. 따라서 개발자는 전체 시스템을 이러한 구성요소의 대규모 연합으로 볼 수 있습니다. 이렇게 하면 다른 애플리케이션과 깔끔하고 원활하게 통합할 수 있으므로 원하는 결과를 반환하도록 코드를 직접 설계해야 합니다.
이 문서에서는 일반적인 끊김 현상 문제와 이를 방지하는 방법에 관해 설명합니다.
데이터 삭제 안함
항상 Android 플랫폼은 모바일 플랫폼이라는 점에 유의하세요. 당연하게 들릴 수도 있겠지만, 언제든지 내 활동 위에 다른 활동 (예: '전화 수신' 앱)이 표시될 수 있다는 점을 기억해야 합니다. 그러면 onSaveInstanceState() 및 onPause() 메서드가 실행되고 애플리케이션이 종료될 수 있습니다.
다른 활동이 표시될 때 사용자가 애플리케이션에서 데이터를 수정하고 있었다면 애플리케이션이 종료될 때 애플리케이션에서 해당 데이터를 잃을 가능성이 높습니다. 물론 진행 중인 작업을 먼저 저장하지 않는 경우 해당합니다. 'Android의 방식'은 입력을 수락하거나 수정하는 Android 애플리케이션에서 onSaveInstanceState() 메서드를 재정의하고 적절한 방식으로 상태를 저장해야 한다는 것입니다. 사용자가 애플리케이션을 다시 방문하면 데이터를 검색할 수 있어야 합니다.
이 동작을 잘 이용하는 대표적인 예는 메일 애플리케이션입니다. 다른 활동이 시작될 때 사용자가 이메일을 작성했다면 애플리케이션은 진행 중인 이메일을 초안으로 저장해야 합니다.
원시 데이터를 노출하지 않음
속옷만 입고 거리를 걷지 않는다면 데이터도 마찬가지입니다. 특정 종류의 애플리케이션을 전 세계에 공개할 수 있지만 이는 일반적으로 바람직하지 않습니다. 원시 데이터를 노출하려면 다른 애플리케이션에서 데이터 형식을 이해해야 합니다. 형식을 변경하면 비슷하게 업데이트되지 않은 다른 애플리케이션이 손상됩니다.
'Android 방식'은 깔끔하고 세심하며 유지관리 가능한 API를 통해 다른 애플리케이션에 데이터를 노출하는 ContentProvider를 만드는 것입니다. ContentProvider를 사용하는 것은 자바 언어 인터페이스를 삽입하여 긴밀하게 결합된 두 코드를 분할하고 구성요소화하는 것과 매우 유사합니다. 즉, ContentProvider에 의해 노출된 인터페이스를 변경하지 않고도 데이터의 내부 형식을 수정할 수 있으며, 이렇게 하면 다른 애플리케이션에 영향을 주지 않습니다.
사용자를 방해하지 않음
사용자가 애플리케이션 (예: 통화 중에 전화 애플리케이션)을 실행 중이라면 의도적으로 실행하는 것이 안전합니다. 따라서 현재 활동에서 사용자 입력에 직접 응답하는 경우를 제외하고 활동 생성을 피해야 합니다.
즉, 백그라운드에서 실행 중인 BroadcastReceivers나 서비스에서 startActivity()를 호출하지 마세요. 이렇게 하면 현재 실행 중인 애플리케이션이 중단되어 사용자가 짜증을 냅니다. 더 심각한 문제는 활동이 '키 입력 밴딧'이 되어 사용자가 이전 활동에 제공하는 도중 입력 중 일부를 수신할 수도 있습니다. 애플리케이션의 기능에 따라 이는 문제가 될 수 있습니다.
대신 백그라운드에서 직접 Activity UI를 생성하는 대신 NotificationManager를 사용하여 알림을 설정해야 합니다. 그러면 상태 표시줄에 표시되며 사용자가 편한 시간에 클릭하여 애플리케이션에서 표시할 내용을 확인할 수 있습니다.
(내 활동이 이미 포그라운드에 있는 경우에는 이 모든 내용이 적용되지 않습니다. 이 경우 사용자는 입력에 대한 응답으로 다음 활동이 표시될 것으로 예상합니다.)
처리할 작업이 많은가요? 스레드로 실행
애플리케이션에서 비용이 많이 들거나 오래 실행되는 계산을 실행해야 하는 경우 스레드로 이동해야 할 수 있습니다. 이렇게 하면 '애플리케이션 응답 없음' 대화상자가 사용자에게 표시되지 않으며, 결과적으로 애플리케이션이 완전히 종료됩니다.
기본적으로 활동의 모든 코드와 활동의 모든 코드는 동일한 스레드에서 실행됩니다. 이 스레드에서는 UI 이벤트도 처리합니다. 예를 들어 사용자가 키를 누르면 키 다운 이벤트가 활동의 기본 스레드 대기열에 추가됩니다. 이벤트 핸들러 시스템은 이 이벤트를 큐에서 신속하게 제거하고 처리해야 합니다. 그러지 않으면 시스템은 몇 초 후에 애플리케이션이 중단되었다고 결론을 내리고 사용자를 위해 애플리케이션을 종료하겠다고 제안합니다.
장기 실행 코드가 있는 경우 활동에서 인라인으로 코드를 실행하면 이벤트 핸들러 스레드에서 실행되어 효과적으로 이벤트 핸들러를 차단합니다. 이렇게 하면 입력 처리가 지연되고 ANR 대화상자가 표시됩니다. 이를 방지하려면 계산을 스레드로 이동합니다. 이 반응성을 위한 디자인 문서에서는 그 방법을 설명합니다.
단일 활동 화면이 과부하되지 않게 방지
사용 가치가 있는 애플리케이션에는 여러 화면이 있을 수 있습니다. UI 화면을 디자인할 때는 여러 Activity 객체 인스턴스를 사용해야 합니다.
개발 배경에 따라, Activity가 애플리케이션의 진입점이라는 점에서 Java 애플릿과 유사한 것으로 해석할 수 있습니다. 하지만 애플릿 서브클래스가 자바 애플릿의 단일 진입점인 경우에는 활동을 애플리케이션의 여러 진입점 중 하나로 간주해야 합니다. 'main' 활동과 다른 활동의 유일한 차이점은 'main' 활동이 AndroidManifest..xml 파일의 'android.intent.action.MAIN' 작업에 관심을 표현한 유일한 활동이라는 것입니다.
따라서 애플리케이션을 설계할 때는 애플리케이션을 Activity 객체의 연합으로 생각하세요. 이렇게 하면 장기적으로 코드를 훨씬 쉽게 유지할 수 있으며 Android의 애플리케이션 기록 및 '백스택' 모델과도 잘 연동됩니다.
시스템 테마 확장
사용자 인터페이스의 디자인과 분위기에 있어서는 잘 어울리는 것이 중요합니다. 예상한 사용자 인터페이스와 대조되는 애플리케이션은 사용자가 싫어합니다. UI를 디자인할 때 가능한 한 UI를 직접 작성하지 않아야 합니다. 대신 테마를 사용하세요. 테마에서 필요한 부분을 재정의하거나 확장할 수 있지만, 적어도 다른 모든 애플리케이션과 동일한 UI 기반에서 시작해야 합니다. 자세한 내용은 스타일 및 테마를 참고하세요.
여러 화면 해상도에서 작동하도록 UI 디자인
Android 지원 기기에 따라 지원되는 화면 해상도가 달라집니다. 일부 앱은 가로 모드로 전환하는 등 즉시 해상도를 변경할 수도 있습니다. 레이아웃과 드로어블이 다양한 기기 화면에 제대로 표시될 수 있을 만큼 유연해야 합니다.
다행히 이 작업은 매우 쉽습니다. 간단히 말하자면, 주요 해상도로 다양한 버전의 아트워크 (사용하는 경우)를 제공한 다음 다양한 크기를 수용할 수 있도록 레이아웃을 디자인해야 합니다. 예를 들어 하드 코딩된 위치를 사용하지 말고 대신 상대 레이아웃을 사용하세요. 그렇게 하면 시스템이 나머지 작업을 처리하고 애플리케이션이 모든 기기에서 멋지게 표시됩니다.
네트워크가 느리다고 가정
Android 기기에는 다양한 네트워크 연결 옵션이 제공됩니다. 모든 기기에 데이터 액세스 프로비저닝이 있지만 일부는 다른 것보다 더 빠릅니다. 하지만 가장 일반적인 공통 분모는 GSM 네트워크의 비 3G 데이터 서비스인 GPRS입니다. 3G 지원 기기조차도 3G가 아닌 네트워크에서 많은 시간을 소비하므로 느린 네트워크는 꽤 오랫동안 현실로 유지됩니다.
따라서 네트워크 액세스 및 대역폭을 최소화하도록 애플리케이션을 항상 코딩해야 합니다. 네트워크가 빠르다고 가정할 수 없으므로 항상 느린 속도에 대비해야 합니다. 사용자가 더 빠른 네트워크를 사용하게 된다면 좋습니다. 사용자의 경험은 개선될 것입니다. 그 반대의 경우를 피하는 것이 좋습니다. 어떤 경우에는 사용할 수 있지만 사용자의 위치에 따라 별다른 작업 속도를 저하시키는 애플리케이션은 인기가 없을 가능성이 높습니다.
한 가지 잠재적인 문제는 에뮬레이터가 데스크톱 컴퓨터의 네트워크 연결을 사용하기 때문에 에뮬레이터를 사용하는 경우 이 트랩에 매우 빠지기 쉽다는 것입니다. 이는 셀 네트워크보다 훨씬 빠르다는 것을 거의 보장하므로 더 느린 네트워크 속도를 시뮬레이션하는 에뮬레이터에서 설정을 변경하는 것이 좋습니다. Android 스튜디오에서 AVD Manager를 사용하거나 에뮬레이터를 시작할 때 명령줄 옵션을 통해 이 작업을 할 수 있습니다.
터치스크린 또는 키보드를 사용하지 않음
Android에서는 다양한 핸드셋 폼 팩터를 지원합니다. 즉, 일부 Android 기기에는 완전한 'QWERTY' 키보드가 있고 다른 기기에는 40키, 12키 또는 다른 키 구성이 있다고 설명합니다. 마찬가지로 일부 기기에는 터치스크린이 있지만 대부분은 그렇지 않습니다.
애플리케이션을 작성할 때 이점에 유의해야 합니다. 특정 키보드 레이아웃을 가정하지 마세요. 물론 그러한 기기에서만 사용할 수 있도록 애플리케이션을 제한하는 데 관심이 있는 경우는 예외입니다.
기기 배터리 절약
휴대기기가 벽에 계속 꽂혀 있으면 움직이지 않습니다. 휴대기기는 배터리로 작동하므로 배터리를 더 오래 충전할수록 모든 사용자, 특히 사용자의 만족도가 높아집니다. 배터리 전원을 가장 많이 소비하는 두 가지 요소는 프로세서와 라디오입니다. 따라서 가능한 한 적은 작업을 하도록 애플리케이션을 작성하고 네트워크를 가능한 한 드물게 사용하도록 애플리케이션을 작성하는 것이 중요합니다.
애플리케이션에서 사용하는 프로세서 시간을 최소화하는 것은 실제로 효율적인 코드 작성에 달려 있습니다. 무선 기능 사용으로 인한 전력 소모를 최소화하려면 오류 조건을 적절하게 처리하고 필요한 항목만 가져와야 합니다. 예를 들어 네트워크 작업이 실패할 경우 계속 재시도하지 마세요. 한 번 실패하면 사용자가 수신이 되지 않기 때문일 수 있으므로 바로 시도하면 다시 실패할 수 있습니다. 배터리 전력을 낭비하기만 하면 됩니다.
사용자는 꽤 똑똑합니다. 프로그램에 전원이 부족하면 이를 알아차릴 것이다. 이 시점에서 확실하게 알 수 있는 것은 프로그램이 너무 오래 설치된 상태로 유지되지 않는다는 것입니다.