blob: 3bbc4745e9e8f35ba25f33d700d653b5b8596e88 [file] [log] [blame]
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>
&#64;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 &lt;package&gt; 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 &lt;package&gt; RUN_IN_BACKGROUND allow}
</pre>
</li>
</ul>