안드로이드 개발 DB 변경 결과 이후 작업을 위한 옵져버 ContentObserver 활용하는 방법

 

환경: Android Studio 3.0.0

 

Content Provider 은 공동으로 관리할 수 있는 저장소 입니다. 간단한 데이터들은 이곳에 저장하거나 꺼내서 사용합니다. 이렇게 공동으로 사용하다 보니 다른 곳에 영향을 주는 값들이 있습니다. 이런 경우 값이 변경되면 통보를 받을 수 있도록 감시 기능을 설정할 수 있습니다. 그것이 바로 ContentObserver 입니다. 또한, SQLite DB 저장 값이 변경되어도 알림을 받을 수 있습니다.

 

ContentObserver 클래스를 상속받아 사용자 정의 Observer 클래스를 만들었습니다. 생성자 함수와 onChange() Override 해서 작성합니다.

private class Observer extends ContentObserver {
    public Observer() {
        super(null);
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        if (!selfChange) {
            // do stuff
            // never called when a thread is deleted
            Log.d("GON", "onChange call");
        }
    }
}

ContentObserver 상속받아 만든 클래스를 등록하는 과정은 다음과 같습니다. registerContentObserver() 함수로 URI ContentObserver 를 등록합니다

private Observer mObserver;
private ContentResolver mCr;

private void registerObserver(){
    Uri URI = Uri.parse("content://sms");

    mCr = getContentResolver();
    mObserver = new Observer();
    mCr.registerContentObserver( URI, true, mObserver );
}

해제는 간단합니다. Observer unregisterContentObserver() 함수를 이용합니다

@Override
protected void onDestroy() {
    super.onDestroy();
    mCr.unregisterContentObserver(mObserver);
}

ContentObserver onChange() 함수를 호출하는 경우는 다음과 같습니다. 주의할 것은 마지막에 getContentResolver().notifyChange() 함수를 실행해야 합니다

// 버튼 클릭
protected void onSendSMS(View v){
    Uri URI = Uri.parse("content://sms");
    String[] columns = {"_id", "date"};
    Cursor cursor = getContentResolver().query(
            URI,
            columns,
            "type=?",
            new String[]{"1"},
            "_id DESC");

    getContentResolver().notifyChange(URI, null);
}

전체 Activity 소스 입니다. 여기에는 퍼미션을 얻는 과정이 있어서 조금 복잡합니다.

import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;


/**
 * Created by gon on 2017-12-12.
 *
 * DB 변경 사항을 알아챌 수 있는 Observer 구현
 */


public class ObserverActivity extends Activity {
    private static final int PERMISSIONS_REQUEST_READ_SMS = 100;
    private Observer mObserver;
    private ContentResolver mCr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_observer);

        callPermission();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mCr.unregisterContentObserver(mObserver);
    }

    private void registerObserver(){
        Uri URI = Uri.parse("content://sms");

        mCr = getContentResolver();
        mObserver = new Observer();
        mCr.registerContentObserver( URI, true, mObserver );
    }

    // 버튼 클릭
    protected void onSendSMS(View v){
        Uri URI = Uri.parse("content://sms");
        String[] columns = {"_id", "date"};
        Cursor cursor = getContentResolver().query(
                URI,
                columns,
                "type=?",
                new String[]{"1"},
                "_id DESC");

        getContentResolver().notifyChange(URI, null);
    }

    private class Observer extends ContentObserver {
        public Observer() {
            super(null);
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            if (!selfChange) {
                // do stuff
                // never called when a thread is deleted
                Log.d("GON", "onChange call");
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {
        if (requestCode == PERMISSIONS_REQUEST_READ_SMS) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted
                registerObserver();
            } else {
                Toast.makeText(this,
                        "Until you grant the permission, we canot display the names",
                        Toast.LENGTH_LONG).show();
            }
        }
    }

    private void callPermission() {
        // Check the SDK version and whether the permission is already granted or not.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                && checkSelfPermission(Manifest.permission.READ_SMS)
                != PackageManager.PERMISSION_GRANTED) {

            requestPermissions(
                    new String[]{Manifest.permission.READ_SMS},
                    PERMISSIONS_REQUEST_READ_SMS);
        } else {
            // 해당 로직으로 이동
            registerObserver();
        }
    }
}

Activity 에서 쓰인 레이아웃 XML 입니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn_sms"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onSendSMS"
        android:text="Observer Check"/>

</android.support.constraint.ConstraintLayout>

안드로이드 개발 DB 변경 결과 이후 작업을 위한 옵져버 ContentObserver 활용하는 방법

 

실행 결과는 Console 에서 확인할 수 있습니다. onChange() 함수를 호출해서 로그를 찍었습니다

안드로이드 개발 DB 변경 결과 이후 작업을 위한 옵져버 ContentObserver 활용하는 방법


Posted by 녹두장군