| page.title=백그라운드 최적화 |
| page.metaDescription=암시적 브로드캐스트에 대한 새로운 제한. |
| page.keywords="android N", "implicit broadcasts", "job scheduler" |
| page.image=images/cards/card-nyc_2x.jpg |
| |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2> |
| 이 문서의 내용 |
| </h2> |
| |
| <ol> |
| <li> |
| <a href="#connectivity-action">CONNECTIVITY_ACTION에 대한 제한</a> |
| </li> |
| |
| <li> |
| <a href="#sched-jobs">무제한 연결에서 네트워크 작업 |
| 예약</a> |
| </li> |
| |
| <li> |
| <a href="#monitor-conn">앱이 실행되는 중에 네트워크 연결 |
| 모니터링</a> |
| </li> |
| |
| <li> |
| <a href="#media-broadcasts">NEW_PICTURE 및 NEW_VIDEO에 |
| 대한 제한</a> |
| </li> |
| |
| <li> |
| <a href="#new-jobinfo">새로운 JobInfo 메서드</a> |
| </li> |
| |
| <li> |
| <a href="#new-jobparam">새로운 JobParameter 메서드</a> |
| </li> |
| |
| <li> |
| <a href="#further-optimization">추가적인 앱 최적화</a> |
| </li> |
| </ol> |
| </div> |
| </div> |
| |
| <p> |
| 백그라운드 프로세스는 메모리와 배터리를 많이 소모할 수 있습니다. 예를 들어, 암시적 브로드캐스트는 |
| 이 브로드캐스트를 수신하도록 등록된 많은 백그라운드 프로세스를 시작할 수 있지만 |
| 해당 프로세스가 많은 작업을 수행하지 못할 경우가 있습니다. 이로 인해 기기 성능과 |
| 사용자 환경에 모두 상당한 영향을 미칠 수 있습니다. |
| </p> |
| |
| <p> |
| 이 문제를 완화하기 위해, Android N은 다음과 같은 제한을 |
| 적용합니다. |
| </p> |
| |
| <ul> |
| <li>브로드캐스트를 수신하도록 매니페스트에 등록되어 있더라도, Preview를 대상으로 하는 앱은 {@link |
| android.net.ConnectivityManager#CONNECTIVITY_ACTION} |
| 브로드캐스트를 수신하지 않습니다. 실행 중인 앱은 {@link android.content.Context#registerReceiver Context.registerReceiver()}로 |
| {@link android.content.BroadcastReceiver}를 등록하여 |
| 여전히 기본 스레드에서 {@code CONNECTIVITY_CHANGE}를 수신할 |
| 수 있습니다. |
| </li> |
| |
| <li>앱은 {@link |
| android.hardware.Camera#ACTION_NEW_PICTURE} 또는 {@link |
| android.hardware.Camera#ACTION_NEW_VIDEO} 브로드캐스트를 송수신할 수 없습니다. 이 최적화는 Preview를 대상으로 |
| 하는 앱뿐 아니라 모든 앱에 영향을 미칩니다. |
| </li> |
| </ul> |
| |
| <p> |
| 앱이 이들 인텐트 중 하나라도 사용하는 경우에는, |
| Android N 기기를 올바로 대상으로 삼을 수 있도록 이들 인텐트에 대한 종속성을 최대한 빨리 제거해야 합니다. |
| Android 프레임워크는 이러한 암시적 브로드캐스트의 |
| 필요성을 줄이기 위한 여러 가지 해결책을 제공합니다. 예를 들어, {@link android.app.job.JobScheduler} |
| 및 <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager"> |
| {@code GcmNetworkManager}</a>는 지정된 |
| 조건(예: 비 데이터 통신 네트워크에 연결)이 충족될 경우 네트워크 작업을 |
| 예약할 수 있는 강력한 메커니즘을 제공합니다. 이제 {@link android.app.job.JobScheduler}를 |
| 사용하여 콘텐츠 제공자의 변경에 대응할 수도 있습니다. {@link android.app.job.JobInfo} |
| 객체는 {@link android.app.job.JobScheduler}가 |
| 작업 예약에 사용하는 매개변수를 캡슐화합니다. 작업 조건이 충족되면 시스템은 |
| 이 작업을 앱의 {@link android.app.job.JobService}에서 실행합니다. |
| </p> |
| |
| <p> |
| 이 문서에서는 대체 메서드(예: {@link android.app.job.JobScheduler})를 |
| 사용하여 이러한 새로운 제한에 맞게 앱을 적용하는 방법에 대해 |
| 배워보겠습니다. |
| </p> |
| |
| <h2 id="connectivity-action"> |
| CONNECTIVITY_ACTION에 대한 제한 |
| </h2> |
| |
| <p> |
| Android N을 대상으로 하는 앱은 {@link |
| android.net.ConnectivityManager#CONNECTIVITY_ACTION} 브로드캐스트를 수신하지 않으며(이 브로드캐스트를 수신하도록 매니페스트에 등록하는 경우), 이 |
| 브로드캐스트에 의존하는 프로세스는 |
| 시작되지 않습니다. 이 경우에는 기기가 고정 요금제 네트워크에 연결될 때, |
| 네트워크 변경 사항을 수신하려는 앱이나 대량의 네트워크 액티비티를 |
| 수행하려는 앱에 문제가 생길 수 있습니다. 이 제한을 해결하기 위한 여러 가지 |
| 해결책이 Android 프레임워크에 이미 있지만, 올바른 해결책을 선택하는 것은 |
| 앱의 용도에 따라 다릅니다. |
| </p> |
| |
| <p class="note"> |
| <strong>참고:</strong> {@link android.content.Context#registerReceiver Context.registerReceiver()}로 |
| 등록된 {@link android.content.BroadcastReceiver}는 앱이 |
| 실행되는 중에 계속해서 이 브로드캐스트를 수신합니다. |
| </p> |
| |
| <h3 id="sched-jobs"> |
| 고정 요금제 연결에서 네트워크 작업 예약 |
| </h3> |
| |
| <p> |
| {@link android.app.job.JobInfo.Builder JobInfo.Builder} 클래스를 |
| 사용하여 {@link android.app.job.JobInfo} 객체를 빌드하는 경우, {@link |
| android.app.job.JobInfo.Builder#setRequiredNetworkType |
| setRequiredNetworkType()} 메서드를 적용하고 {@link android.app.job.JobInfo |
| JobInfo.NETWORK_TYPE_UNMETERED}를 작업 매개변수로 전달합니다. 다음의 코드 샘플에서는 기기가 비 데이터 통신 |
| 네트워크에 연결되어 충전 중일 때 실행할 서비스를 |
| 예약합니다. |
| </p> |
| |
| <pre> |
| public static final int MY_BACKGROUND_JOB = 0; |
| ... |
| public static void scheduleJob(Context context) { |
| JobScheduler js = |
| (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); |
| JobInfo job = new JobInfo.Builder( |
| MY_BACKGROUND_JOB, |
| new ComponentName(context, MyJobService.class)) |
| .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) |
| .setRequiresCharging(true) |
| .build(); |
| js.schedule(job); |
| } |
| </pre> |
| |
| <p> |
| 작업의 조건이 충족되면, 앱은 |
| {@link android.app.job.JobService#onStartJob onStartJob()} 메서드를 지정된 {@code JobService.class}에서 실행하기 위한 콜백을 |
| 수신합니다. {@link |
| android.app.job.JobScheduler} 구현의 더 많은 예를 보려면, <a href="{@docRoot}samples/JobScheduler/index.html">JobScheduler 샘플 앱</a>을 참조하세요. |
| </p> |
| |
| <p> |
| GMSCore 서비스를 사용하고 Android 5.0(API 레벨 21) 이하를 대상으로 하는 앱은 <a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager"> |
| {@code GcmNetworkManager}</a>를 사용하고 {@code Task.NETWORK_STATE_UNMETERED}를 |
| 지정할 수 있습니다. |
| </p> |
| |
| <h3 id="monitor-conn"> |
| 앱이 실행되는 중에 네트워크 연결 모니터링 |
| </h3> |
| |
| <p> |
| 실행 중인 앱은 등록된 {@link android.content.BroadcastReceiver}로 {@code CONNECTIVITY_CHANGE}를 여전히 수신할 수 |
| 있습니다. 하지만 {@link |
| android.net.ConnectivityManager} API는 지정된 네트워크 조건이 충족될 경우에만 콜백을 요청하는 |
| 더욱 강력한 메서드를 제공합니다. |
| </p> |
| |
| <p> |
| {@link android.net.NetworkRequest} 객체는 {@link android.net.NetworkCapabilities}의 |
| 관점에서 네트워크 콜백의 매개변수를 정의합니다. {@link |
| android.net.NetworkRequest.Builder NetworkRequest.Builder} 클래스로 {@link android.net.NetworkRequest} 객체를 |
| 생성합니다. 이어서 {@link |
| android.net.ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest, |
| android.net.ConnectivityManager.NetworkCallback) registerNetworkCallback()} |
| 이 {@link android.net.NetworkRequest} 객체를 시스템에 전달합니다. 네트워크 조건이 충족되면, 앱은 {@link |
| android.net.ConnectivityManager.NetworkCallback} 클래스에 정의된 {@link android.net.ConnectivityManager.NetworkCallback#onAvailable |
| onAvailable()} 메서드를 |
| 실행하기 위한 콜백을 |
| 수신합니다. |
| </p> |
| |
| <p> |
| 앱이 종료되거나 앱이 {@link android.net.ConnectivityManager#unregisterNetworkCallback |
| unregisterNetworkCallback()}을 호출할 때까지 계속해서 |
| 콜백을 수신합니다. |
| </p> |
| |
| <h2 id="media-broadcasts"> |
| NEW_PICTURE 및 NEW_VIDEO에 대한 제한 |
| </h2> |
| |
| <p> |
| Android N에서 앱은 {@link |
| android.hardware.Camera#ACTION_NEW_PICTURE} 또는 {@link |
| android.hardware.Camera#ACTION_NEW_VIDEO} 브로드캐스트를 송수신할 수 없습니다. 이 제한은 새로운 이미지나 |
| 동영상을 처리하기 위해 여러 앱을 깨워야 하는 경우, 성능 및 사용자 환경에 |
| 미치는 영향을 줄여줍니다. Android N은 |
| {@link android.app.job.JobInfo} 및 {@link |
| android.app.job.JobParameters}를 확장하여 대체 해결책을 제공합니다. |
| </p> |
| |
| <h3 id="new-jobinfo"> |
| 새로운 JobInfo 메서드 |
| </h3> |
| |
| <p> |
| 콘텐츠 URI 변경에 대한 작업을 트리거하기 위해, Android N은 |
| 다음과 같은 메서드로 {@link android.app.job.JobInfo} API를 확장합니다. |
| </p> |
| |
| <dl> |
| <dt> |
| {@code JobInfo.TriggerContentUri()} |
| </dt> |
| |
| <dd> |
| 콘텐츠 URI 변경에 대한 작업을 트리거하는 데 필요한 매개변수를 캡슐화합니다. |
| </dd> |
| |
| <dt> |
| {@code JobInfo.Builder.addTriggerContentUri()} |
| </dt> |
| |
| <dd> |
| {@code TriggerContentUri} 객체를 {@link |
| android.app.job.JobInfo}에 전달합니다. {@link android.database.ContentObserver}는 |
| 캡슐화된 콘텐츠 URI를 모니터링합니다. 하나의 작업과 연관된 여러 {@code |
| TriggerContentUri} 객체가 있는 경우, 콘텐츠 URI 중 하나에서만 변경이 보고되더라도 시스템이 |
| 콜백을 제공합니다. |
| </dd> |
| |
| <dd> |
| 지정된 URI의 하위 항목이 하나라도 변경되면, {@code TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS} 플래그를 |
| 추가하여 작업을 트리거합니다. 이 플래그는 |
| {@link |
| android.content.ContentResolver#registerContentObserver |
| registerContentObserver()}로 전달된 {@code notifyForDescendants} 매개변수에 해당합니다. |
| </dd> |
| </dl> |
| |
| <p class="note"> |
| <strong>참고:</strong> {@code TriggerContentUri()}는 {@link android.app.job.JobInfo.Builder#setPeriodic |
| setPeriodic()} 또는 {@link android.app.job.JobInfo.Builder#setPersisted |
| setPersisted()}와 |
| 조합으로 사용될 수 없습니다. 콘텐츠 변경을 계속해서 모니터링하려면, 앱의 {@link |
| android.app.job.JobService}가 가장 최근 콜백의 처리를 완료하기 전에 새로운 |
| {@link android.app.job.JobInfo}를 예약하세요. |
| </p> |
| |
| <p> |
| 다음 샘플 코드에서는 콘텐츠 URI, {@code MEDIA_URI}의 |
| 변경을 시스템이 보고할 때 트리거할 작업을 예약합니다. |
| </p> |
| |
| <pre> |
| public static final int MY_BACKGROUND_JOB = 0; |
| ... |
| public static void scheduleJob(Context context) { |
| JobScheduler js = |
| (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); |
| JobInfo.Builder builder = new JobInfo.Builder( |
| MY_BACKGROUND_JOB, |
| new ComponentName(context, MediaContentJob.class)); |
| builder.addTriggerContentUri( |
| new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, |
| JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); |
| js.schedule(builder.build()); |
| } |
| </pre> |
| <p> |
| 지정된 콘텐츠 URI에서의 변경을 시스템이 보고할 때, |
| 앱이 콜백을 수신하고 {@link android.app.job.JobParameters} 객체가 |
| {@code MediaContentJob.class}의 {@link android.app.job.JobService#onStartJob onStartJob()}메서드에 |
| 전달됩니다. |
| </p> |
| |
| <h3 id="new-jobparam"> |
| 새로운 JobParameter 메서드 |
| </h3> |
| |
| <p> |
| 또한, Android N에서는 어떤 콘텐츠 기관과 |
| URI가 해당 작업을 트리거했는지에 대한 유용한 정보를 앱이 |
| 수신할 수 있도록 {@link android.app.job.JobParameters}를 확장합니다. |
| </p> |
| |
| <dl> |
| <dt> |
| {@code Uri[] getTriggeredContentUris()} |
| </dt> |
| |
| <dd> |
| 작업을 트리거한 URI의 배열을 반환합니다. 작업을 트리거한 |
| URI가 없거나(예: 시한 또는 기타 이유로 인해 작업이 트리거된 경우) 또는 |
| 변경된 URI의 수가 50보다 크면 {@code |
| null}이 됩니다. |
| </dd> |
| |
| <dt> |
| {@code String[] getTriggeredContentAuthorities()} |
| </dt> |
| |
| <dd> |
| 작업을 트리거한 콘텐츠 기관의 문자열 배열을 반환합니다. |
| 반환된 배열이 {@code null}이 아닌 경우, {@code getTriggeredContentUris()}를 |
| 사용하여 변경된 URI의 세부정보를 검색합니다. |
| </dd> |
| </dl> |
| |
| <p> |
| 다음 샘플 코드에서는 {@link |
| android.app.job.JobService#onStartJob JobService.onStartJob()} 메서드를 재정의하고 |
| , 작업을 트리거한 콘텐츠 기관과 URI를 기록합니다. |
| </p> |
| |
| <pre> |
| @Override |
| public boolean onStartJob(JobParameters params) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("Media content has changed:\n"); |
| if (params.getTriggeredContentAuthorities() != null) { |
| sb.append("Authorities: "); |
| boolean first = true; |
| for (String auth : |
| params.getTriggeredContentAuthorities()) { |
| if (first) { |
| first = false; |
| } else { |
| sb.append(", "); |
| } |
| sb.append(auth); |
| } |
| if (params.getTriggeredContentUris() != null) { |
| for (Uri uri : params.getTriggeredContentUris()) { |
| sb.append("\n"); |
| sb.append(uri); |
| } |
| } |
| } else { |
| sb.append("(No content)"); |
| } |
| Log.i(TAG, sb.toString()); |
| return true; |
| } |
| </pre> |
| |
| <h2 id="further-optimization"> |
| 추가적인 앱 최적화 |
| </h2> |
| |
| <p> |
| 저용량 메모리 기기나 저용량 메모리 조건에서 |
| 앱이 실행되도록 최적화하면 성능과 사용자 환경을 개선할 수 있습니다. 백그라운드 서비스에 대한 종속성과 정적으로 등록된 |
| 암시적 브로드캐스트 수신기에 대한 종속성을 제거하면 해당 기기에서 앱을 |
| 더욱 빨리 실행할 수 있습니다. Android N은 이러한 문제 중 일부를 줄이기 위한 |
| 조치를 취하고 있지만, 백그라운드 |
| 프로세스를 전혀 사용하지 않고 앱이 실행되도록 |
| 최적화하는 것이 좋습니다. |
| </p> |
| |
| <p> |
| Android N에서는 백그라운드 프로세스를 |
| 비활성화하고 앱 동작을 테스트하는 데 사용할 수 있는 몇 가지 추가적인 <a href="{@docRoot}tools/help/adb.html">ADB(Android 디버그 브리지)</a> 명령을 도입했습니다. |
| </p> |
| |
| <ul> |
| <li>암시적 브로드캐스트와 백그라운드 서비스를 사용할 |
| 수 없는 조건을 시뮬레이션하려면 다음 명령을 입력합니다. |
| </li> |
| |
| <li style="list-style: none; display: inline"> |
| <pre class="no-pretty-print"> |
| {@code $ adb shell cmd appops set <package> RUN_IN_BACKGROUND ignore} |
| </pre> |
| </li> |
| |
| <li>암시적 브로드캐스트와 백그라운드 서비스를 다시 활성화하려면 |
| 다음 명령을 입력합니다. |
| </li> |
| |
| <li style="list-style: none; display: inline"> |
| <pre class="no-pretty-print"> |
| {@code $ adb shell cmd appops set <package> RUN_IN_BACKGROUND allow} |
| </pre> |
| </li> |
| </ul> |