[Android N] Background Optimizations - CONNECTIVITY_ACTION

CONNECTIVITY_ACTION 브로드캐스트는 네트워크 연결 상태 변화를 알려줍니다. LTE 모바일 네트워크에서 Wi-Fi로 변경되는 경우 등이죠. Android 6.0까지는 애플리케이션의 manifest 파일에 CONNECTIVITY_ACTION 브로드캐스트를 등록할 수 있었지만 N 부터는 허용하지 않습니다. 

왜 그럴까요? 네트워크 연결 상태가 변할 때 마다 CONNECTIVITY_ACTION을 받기 위해 등록된 앱들이 실행되면 메모리, 배터리 등의 자원을 낭비하게 되겠죠. 막상 실행된 앱이 할일도 없는데 말이죠. 대신 Android N의 경우 아래 3가지 방법을 이용하여 네트워크 상태 변화를 확인할 수 있습니다.
  1. Context.registerReceiver()로 CONNECTIVITY_ACTION 브로드캐스트를 받도록 등록할 수 있습니다
  2. JobScheduler를 이용하여 특정 조건이 되면 JobService의 onStartJob()이 호출 되도록 합니다
  3. ConnectivityManager를 이용하여 특정 조건의 네트워크 상태가 되면 콜백이 불리도록 합니다
각 방법에 대한 예제 코드를 보죠.
    getApplicationContext().registerReceiver(new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            Log.d(LOG_TAG, "onReceive");
        }
    }, new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION));

registerReceiver 를 호출하여 CONNECTIVITY_ACTION 브로드캐스트를 받도록 합니다. 네트워크의 상태가 변할 때 마다 onReceive가 호출됩니다. (예: LTE => Wi-Fi로 전환 혹은 Wi-Fi => LTE로 전환). 현재 네트워크의 상태는 ConnectivityManager에서 확인 할수 있습니다.
    ConnectivityManager cm =
        (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo ni = cm.getActiveNetworkInfo();
    if (ni != null) {
        Log.d(tag, ni.toString());
    }

JobScheduler를 이용하면 특정 조건들이 맞아 떨어질때 서비스가 실행되도록 만들 수 있습니다. 아래 예제 코드의 경우는 기기가 충전 중이고 비과금(무료) 네트워크에 연결된 경우 MyJobService 클래스에 구현된 서비스를 실행합니다.
    final Context context = getApplicationContext();
    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);

조건이 맞으면 JobService의 onStartJob이 호출됩니다. 
public class MyJobService extends JobService {
    private final String LOG_TAG = "MyJobService";

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        Log.d(LOG_TAG, "onStartJob");
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
        return false;
    }
}

JobService를 상속받아 구현한 클래스는 아래와 같이 manifest 파일에 서비스로 등록해 주어야 합니다. (exported는 true로 변경할 수 있습니다.)

<service android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false">
</service>

마지막으로 ConnectivityManager의 registerNetworkCallback()을 이용하여 특정 조건의 네트워크를 쓸 수 있는 상태가 되면 콜백이 호출되도록 할 수도 있습니다. 아래 예제는 비과금 Wi-Fi 네트워크에 연결되면 onAvailable이 호출되도록 합니다.
    final Context context = getApplicationContext();
    ConnectivityManager cm =
            (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkRequest request = new NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .build();
    cm.registerNetworkCallback(request, new ConnectivityManager.NetworkCallback() {
        public void onAvailable (Network network) {
            Log.d(LOG_TAG, "onAvailable");
        }
    });


https://github.com/wonkim/BackgroundOptimizations에서 전체 예제 코드를 받으세요.

이 블로그의 인기 게시물

Wireless: HotSpot 2.0 이란?

Apple M1 Mac Mini에서 이더리움 (Ethereum) 채굴하기

Java: Java for Game? Java가 Game 개발에 어울릴까?