728x90

연락처(Contacts) ContactHelper Class  메소드를 세부적으로 추가했다.

첨부된 파일의 소스는 한명의 데이터가 분리되어 표기되기 때문에 실제 연락처 소스로 활용하기에는 부족하다. 테스트 용도로는 매우 좋다.

Cursor 쿼리 중심으로 이해하기 쉽게 코드를 수정 보완해서 작성했다.

SQLiteHelper 에서 사용하는 Cursor 와는 개념은 비슷한데 약간 다르다.

아래 코드 중에서 100% 완료 상태가 아닌 테스트 중인 것을 그대로 올린 것도 있으므로 필요하신 분은 수정해서 사용하면 될 것으로 본다.

구글링을 하고 본인의 생각을 담아서 코드를 추가하면 유용하게 사용할 수 있는 좋은 자료라고 본다.


import java.util.ArrayList;

import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.RawContacts;
import android.widget.Toast;

public class ContactHelper {

    // Display Name 이 포함된 모든 Cursor 반환
    public static Cursor getContactCursorFromDisplayNameLIKE(ContentResolver contactHelper, String display_name) {

        // 검색할 칼럼 정하기, null 이면 모든 필드
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER };
        // Cursor를 얻기 위한 쿼리 조건
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like \'%" + display_name + "%\'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;

        try {
            if (display_name != null && !display_name.equals("")) {
                cursor = contactHelper.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, where, null,
                        sortOrder);
            } else {
                cursor = contactHelper.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null,
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
            }
            cursor.moveToFirst();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return cursor;
    }

    // Display Name 으로 모든 Cursor 반환
    public static Cursor getContactCursorFromDisplayName(ContentResolver contactHelper, String display_name) {

        // 검색할 칼럼 정하기, null 이면 모든 필드
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER };
        // Cursor를 얻기 위한 쿼리 조건
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ='" + display_name + "'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;

        try {
            if (display_name != null && !display_name.equals("")) {
                cursor = contactHelper.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, where, null,
                        sortOrder);
            }
            cursor.moveToFirst();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return cursor;
    }

    public static Cursor getDisplayNameFromNumber(ContentResolver contactHelper, String number) {

        // 참조 https://developer.android.com/reference/android/provider/ContactsContract.PhoneLookup.html
        // Android 2.0 and later
        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

        // 검색할 칼럼 정하기, null 이면 모든 필드
        String[] projection = { PhoneLookup._ID, PhoneLookup.DISPLAY_NAME, PhoneLookup.NUMBER };

        Cursor cursor = null;

        try {
            if (number != null && !number.equals("")) {
                cursor = contactHelper.query(contactUri, projection, null, null, null);
                if (cursor.getCount() > 0) {
                    while (cursor.moveToNext()) {
                        long rawContactId = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
                        System.out.println("Contact ID from number : " + rawContactId);
                        System.out.println("Contact DISPLAY_NAME : "
                                + cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME)));
                        System.out.println("Contact NUMBER : " + cursor.getString(cursor.getColumnIndex(PhoneLookup.NUMBER)));
                    }
                    return cursor;
                }

            } else {
                System.out.println("전화번호 검색어가 입력되지 않았습니다 ");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static long getContactIDFromName(ContentResolver contactHelper, String display_name) {
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

        String[] projection = { ContactsContract.Contacts._ID };
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        String[] whereParams = null; // new String[] {display_name};
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;

        try {
            cursor = contactHelper.query(contactUri, null, where, whereParams, sortOrder);

            if (cursor.moveToFirst()) {
                System.out.println("ContactID from display_name : "
                        + cursor.getLong(cursor.getColumnIndex(ContactsContract.Contacts._ID)));
                return cursor.getLong(cursor.getColumnIndex(ContactsContract.Contacts._ID));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
                cursor = null;
            }
        }

        return -1;
    }

    // 전화번호에서 ContactID 획득
    private static long getContactIDFromNumber(ContentResolver contactHelper, String number) {
        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

        String[] projection = { PhoneLookup._ID };
        Cursor cursor = null;

        try {
            cursor = contactHelper.query(contactUri, projection, null, null, null);

            if (cursor.moveToFirst()) {
                System.out.println("ContactID from number : " + cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID)));
                return cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
            }

            return -1;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
                cursor = null;
            }
        }

        return -1;
    }

    // 연락처 추가 (이름 + 전화번호), 기존 개발자 구현 완료사항
    public static boolean insertContact(ContentResolver contactHelper, String firstName, String mobileNumber) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();

        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null).build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, firstName).build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, mobileNumber)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, Phone.TYPE_MOBILE).build());

        try {
            // 연락처 제공자는 applyBatch()에서의 모든 작업을 하나의 트랜잭션으로서 수행
            contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (Exception e) {
            return false;
        }

        return true;
    }

    // 구한 ID 기준으로 연락처 삭제
    // 성명 검색으로 구한 ContactID는 삭제가 안되고, Phone Number 로 구한 ContactID는 삭제가 정상처리됨
    public static void deleteContactFromgetContactID(ContentResolver contactHelper, long getContactId) {
        System.out.println("Contact ID : " + getContactId);
        String where = RawContacts.CONTACT_ID + " = " + getContactId;
        contactHelper.delete(RawContacts.CONTENT_URI, where, null);
    }

    // 전화번호 기준으로 연락처 삭제 (구현 완료)
    public static void deleteContactFromNumber(ContentResolver contactHelper, String number) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        String[] WhereArgs = new String[] { String.valueOf(getContactIDFromNumber(contactHelper, number)) };

        ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)
                .withSelection(RawContacts.CONTACT_ID + "=?", WhereArgs).build());
        try {
            contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
    }

    // 성명 기준으로 동일한 성명을 가진 모든 연락처 삭제 (구현 완료)
    public static void deleteAllContactFromName(ContentResolver contactHelper, String display_name) {
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        contactHelper.delete(RawContacts.CONTENT_URI, where, null);
    }

    // 성명 기준으로 동일한 성명을 가진 모든 연락처 삭제 -- 진행중
    public static void deleteAllContactFromName2(ContentResolver contactHelper, String display_name) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
       
        Cursor cursor = null;
        cursor = getContactCursorFromDisplayName(contactHelper, display_name);
        if (cursor != null && cursor.getCount() > 0) {
            cursor.moveToFirst();
            while (cursor.moveToNext()) {
                String number = cursor.getString(2); // 전화번호 구하기
                // 전화번호 기준으로 ContactID 구하기
                System.out.println("Contact Phone Number : " + number);
                long rawContactId = getContactIDFromNumber(contactHelper, number);
                if (rawContactId > 0) {
                    String where = RawContacts.CONTACT_ID + "=" + rawContactId;
                    //contactHelper.delete(RawContacts.CONTENT_URI, where, null);
                   
                    ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)
                            .withSelection(where, null).build());
                    try {
                        contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    } catch (OperationApplicationException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

    // 성명 포함 연락처 삭제 (구현 완료)
    public static void deleteContactFromNameLIKE(ContentResolver contactHelper, String display_name) {
        System.out.println("Contact Name Search : " + display_name);
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.NUMBER }; // 검색할 칼럼 정하기
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " like \'%" + display_name + "%\'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;
        try {
            if (display_name != null && !display_name.equals("")) {
                cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
                if (cursor.getCount() > 0) {
                    // cursor.moveToFirst();
                    while (cursor.moveToNext()) {
                        long rawContactId = cursor.getLong(cursor.getColumnIndex(Phone._ID));
                        System.out.println("Contact ID from number : " + rawContactId);
                        String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                        System.out.println("Contact Phone Number : " + phoneNO);
                        deleteContactFromNumber(contactHelper, phoneNO);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 성명 + 전화번호 기준으로 ContactId 구하기 -- 구현중
    public static long getContactIdFromNameAndNumber(ContentResolver contactHelper, String display_name, String number) {
        long rawContactId;
        // 먼저 이름기준으로 Cursor 를 구한 다음에 폰 번호 기준 ID 구한다.
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.NUMBER }; // 검색할칼럼 정하기
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;
        try {
            if (display_name != null && !display_name.equals("") && number != null && !number.equals("")) {
                cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
                if (cursor.getCount() > 0) {
                    while (cursor.moveToNext()) {
                        long getContactId = cursor.getLong(cursor.getColumnIndex(Phone._ID));
                        System.out.println("Contact ID from number : " + getContactId);
                        String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                        System.out.println("Contact Phone Number : " + phoneNO);
                        rawContactId = getContactIDFromName(contactHelper, phoneNO);
                        System.out.println("Contact ID from Phone Number : " + rawContactId);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }

    // 성명 + 전화번호 기준으로 연락처 삭제 (동명이인 고려) -- 진행중
    public static void deleteContactFromNameAndNumber(ContentResolver contactHelper, Context context, String display_name,
            String number) {
        // 로직 개념 : 이름 검색으로 전화번호를 구한 다음에, 전화번호 기준으로 ContactID 를 구하는 순서로 로직 구현
        number = number.replaceAll("[^0-9]", ""); // 숫자만 추출
        // 이름 + 전화번호 조건으로 처리하는 로직이 없는 듯....
        // String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME +
        // " = '" + display_name + "' AND "
        // + ContactsContract.CommonDataKinds.Phone.NUMBER + " = '" + number +
        // "' AND "
        // + ContactsContract.CommonDataKinds.Phone.TYPE + "=" +
        // ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE + "";
        Uri contactUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.NUMBER }; // 검색할 칼럼 정하기
        String where = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = '" + display_name + "'";
        String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
        Cursor cursor = null;
        try {
            if (display_name != null && !display_name.equals("") && number != null && !number.equals("")) {
                cursor = contactHelper.query(contactUri, projection, where, null, sortOrder);
                if (cursor.getCount() > 0) {
                    // cursor.moveToFirst();
                    while (cursor.moveToNext()) {
                        long getContactId = cursor.getLong(cursor.getColumnIndex(Phone._ID));
                        String phoneNO = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
                        System.out.println("Contact Phone Number : " + phoneNO);
                        long rawContactId = getContactIDFromNumber(contactHelper, phoneNO);
                        System.out.println("Contact ID from Number : " + rawContactId);
                        deleteContactFromNumber(contactHelper, phoneNO);
                        Toast.makeText(context, "getIDFromName : " + getContactId + " getIDFromNumber : " + rawContactId,
                                Toast.LENGTH_LONG).show();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 모든 연락처 삭제(구현완료)
    public static void deleteAllContact(ContentResolver contactHelper) {
        contactHelper.delete(RawContacts.CONTENT_URI, null, null);
    }

}



MainActivity.java 에서 사용법 예제

예제라고 할 순 없고 테스트 중인 것을 적었다.

public class MainActivity extends ListActivity {

    private ArrayList<String> contactID;
    private ArrayList<String> contactNames;
    private ArrayList<String> contactNumbers;
    ArrayAdapter<String> adapter;
    private Cursor cursor;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button btn_Test1 = (Button) findViewById(R.id.btn_CustomDelete1);
        Button btn_Test2 = (Button) findViewById(R.id.btn_CustomDelete2);

        contactID = new ArrayList<String>();
        contactNames = new ArrayList<String>();
        contactNumbers = new ArrayList<String>();

        cursor = ContactHelper.getContactCursorFromDisplayNameLIKE(getContentResolver(), "");
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            contactID.add(cursor.getString(0));
            contactNames.add(cursor.getString(1));
            contactNumbers.add(cursor.getString(2));
            cursor.moveToNext();
        }

        adapter = new MyAdapter(this, android.R.layout.simple_list_item_1, R.id.tvNameMain, contactNames);
        setListAdapter(adapter);

        // 추가 테스트
        // Cursor cursor1 =
        // ContactHelper.getDisplayNameFromNumber(getContentResolver(), "010-1234-0401");
        // System.out.println("Contact Cursor Return !!");
        // if (cursor1 != null) {
        // cursor1.moveToFirst();
        // while (!cursor1.isAfterLast()) {
        // System.out.println("ContactId =" + cursor1.getString(0) + " 성명: " +
        // cursor1.getString(1) + " 휴대폰번호:"
        // + cursor1.getString(2));
        // cursor1.moveToNext();
        // }
        // }

        btn_Test1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 성명 포함 삭제 테스트
                // 이름 검색으로 구한 ContactID 로는 삭제가 안되나, Number 로 구한 ContactID로는 삭제가
                // 됨
                // ContactHelper.deleteContactFromNameLIKE(getContentResolver(),
                // "개발");
                // ContactHelper.deleteContactFromgetContactID(getContentResolver(),53360);
                ContactHelper.deleteContactFromgetContactID(getContentResolver(), 10674);
                adapter.notifyDataSetChanged();
                // 현재 Activity 갱신처리
                finish();
                startActivity(getIntent());
            }
        });

        btn_Test2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // 전화번호 삭제 테스트
                        // ContactHelper.deleteContactFromNameAndNumber(getContentResolver(), MainActivity.this, "테스트", "010-1212-7710");
                        ContactHelper.deleteAllContactFromName(getContentResolver(), "개발자");
                    }
                });

                // 현재 Activity 갱신처리
                finish();
                startActivity(getIntent());

            }
        });

    }

    private class MyAdapter extends ArrayAdapter<String> {

        public MyAdapter(Context context, int resource, int textViewResourceId, ArrayList<String> conNames) {
            super(context, resource, textViewResourceId, conNames);

        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            View row = setList(position, parent);
            return row;
        }

        private View setList(int position, ViewGroup parent) {
            LayoutInflater inf = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            View row = inf.inflate(R.layout.liststyle, parent, false);

            TextView tvID = (TextView) row.findViewById(R.id.tvContactID);
            TextView tvName = (TextView) row.findViewById(R.id.tvNameMain);
            TextView tvNumber = (TextView) row.findViewById(R.id.tvNumberMain);

            Button btn_Add = (Button) row.findViewById(R.id.btn_AddContact);
            Button btn_Del = (Button) row.findViewById(R.id.btn_deleteContact);

            tvID.setText("ContactID : " + contactID.get(position));
            tvName.setText(contactNames.get(position));
            tvNumber.setText("No: " + contactNumbers.get(position));

            btn_Add.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, AddContact.class);
                    startActivity(intent);
                }
            });

            btn_Del.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, DeleteContacts.class);
                    startActivity(intent);
                }
            });

            return row;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater imf = getMenuInflater();
        imf.inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.item1) {
            Intent intent = new Intent(MainActivity.this, AddContact.class);
            startActivity(intent);
        } else if (item.getItemId() == R.id.item2) {
            Intent intent = new Intent(MainActivity.this, DeleteContacts.class);
            startActivity(intent);
        }
        return super.onOptionsItemSelected(item);
    }
}
 


테스트에 사용한 파일

본 파일은 구글링으로 구한 파일을 가지고 이해하기 쉽게 코드를 상당히 수정하고, 연락처 삭제 중심으로 코드를 추가 구현했다.

테스트 환경 : Eclipse

안드로이드 스튜디오에서 테스트하려면 코드가 복잡한 것이 없으므로 변환하면 될 것으로 본다.

Android-Contacts.zip


Android Studio 버전으로 수정한 코드는 http://link2me.tistory.com/1305 에 올려져 있다.

보완해서 테스트 하고 있는 중이라 약간 더 코드가 수정되었다.

블로그 이미지

Link2Me

,
728x90

Android Contacts 를 검색하고 동일 정보가 있으면 삭제하고 신규로 데이터를 저장하는 로직이 있어서 아무 생각없이 잘 될 것이라는 믿음(?)으로 소스를 사용하다가 주소록을 2,000 개 이상 동시 저장하는 걸 테스트 하는데 너무 느려서 구글링으로 예제 소스 하나 받아서 테스트를 해보니 동일한 자료가 엄청나게 저장되어 있는 걸 알았다.

삼성폰이 기본 제공하는 연락처 앱에서는 데이터가 딱 저장한 개수만큼만 보인다.

데이터 삭제가 제대로 되는지 확인해봤더니 삭제가 안되고 있더라.

계속 삽질을 하다가 Easy Contacts Delete 라는 어플을 받아서 전체를 선택하고 삭제를 했더니 모든 데이터가 삭제되었다.


연락처(Contacts) 에 대한 기본 개념이 부족해서 해결이 제대로 안되는 것이라 집중적으로 관련 자료를 검색하고 책을 보면서 정리하고 테스트 해보고 있다.

Display_Name 으로 검색한 ContactID 와 Phone Number 로 검색한 ContactID 를 정확하게 구현해주어야 한다는 걸 테스트를 통해서 알게되었고, Phone Number 기준으로 얻은 ContactID 로 삭제가 잘 된다는 걸 알았다.


도전의 절반은 스키마를 마스터하고, 각 테이블이 다른 테이블과 어떻게 상호 작용하는지를 이해하는데 있다.


주소록 DB는 /data/data/com.android.providers.contacts/databases/contacts2.db 에 있는데 접근이 불가능하다.

contacts database는 Provider URI 를 통해서 접근할 수 있다.

Stackoverflow 보면 https://developer.android.com/guide/topics/providers/contacts-provider.html 사이트 참조하라고 나온다.


Contacts API 2.0 에서는, 연락처(Contacts)은 다음 세 테이블로 구성되어 있다.


  ContactsContract.Contacts table

 - 고유한 사용자(people) 정보를 표시하는 테이블

 - https://developer.android.com/reference/android/provider/ContactsContract.Contacts.html 칼럼 확인


  ContactsContract.RawContacts table

 - user account and type 을 기준으로, 한 사용자 정보 요약을 포함하는 테이블

 - https://developer.android.com/reference/android/provider/ContactsContract.RawContacts.html 에서 칼럼 확인

 - ContactsContract.RawContacts.CONTACT_ID = Contacts._ID 값과 일치


  ContactsContract.Data table

 - E-Mail 주소나 휴대폰번호 같은 RawContacts 테이블의 세부 정보를 포함하는 테이블
 - ContactsContract.Data.RAW_CONTACT_ID = ContactsContract.RawContacts._ID 값과 일치

 - https://developer.android.com/reference/android/provider/ContactsContract.Data.html 에서 칼럼 확인

 - 15개의 일반 열 중에서 DATA1부터 DATA15까지는 일반적으로 이용할 수 있고 이외에 추가로 마련된 네 개의 일반 열, 즉 SYNC1부터 SYNC4까지는 동기화 어댑터 전용이다.

 - 표시 이름, 전화 번호, 이메일, 우편 주소, 사진 및 웹사이트 세부 정보 행은 모두 ContactsContract.Data 테이블에서 찾을 수 있다.


모든 테이블에는 테이블명._ID 가 있다.


위 도식도에 나온 ID 칼럼이 서로 어떻게 연관되어 있는지를 아는것이 가장 중요하다.

데이터를 수정(Update)하거나 삭제(Delete)할 때 정확하게 정보를 업데이트할 수 있다.

즉 rawContactId 값을 구하는 걸 잘못 구하면 데이터 수정/삭제가 제대로 안된다는 것이다.

이 개념 이해하느라고 정말 많은 시간을 할애하였다.

구글링해도 이런 내용은 나오지 않고 그냥 소스 코드 예제만 좀 나온다.

검색 키워드 찾는 방법을 잘못하니까 예제 찾기도 쉽지 않더라.


원시 연락처의 이름은 ContactsContract.RawContacts에 있는 자신의 행에 저장되지 않고,

ContactsContract.CommonDataKinds.StructuredName 행에 있는 ContactsContract.Data 테이블에 저장된다.
원시 연락처의 데이터는 원시 연락처의 _ID 값과 연결된ContactsContract.Data 행에 저장된다.
하나의 원시 연락처에 같은 유형 데이터의 인스턴스가 여러 개 있을 수 있다.
ㅇ MIMETYPE
  - 사용자 지정 MIME 유형으로 표현된다.
  - 연락처 제공자는 ContactsContract.CommonDataKinds의 서브클래스에서 정의된 MIME 유형을 사용한다.

ㅇ 연락처 제공자는 기존 연락처 어느 것과도 일치하지 않는 새로운 원시 연락처가 추가되면 새로운 연락처를 생성한다.
  애플리케이션이나 동기화 어댑터가 기존 연락처와 일치하는 새로운 원시 연락처를 생성하면, 새로운 원시 연락처는 기존 연락처에 통합된다.
ㅇ 연락처 제공자가 연락처를 자동으로 관리하므로, 통합이나 동기화에 응답하여 연락처 행의 _ID 값을 변경할 수도 있다.
ㅇ 사용자 프로필에 액세스하기 위한 상수는 ContactsContract.Profile 클래스에서 이용할 수 있다.
  - 사용자 프로필에 액세스하려면 특수 권한이 필요하다.
  - android.Manifest.permission#READ_PROFILE과 android.Manifest.permission#WRITE_PROFILE 권한이 필요
  - 권한 android.Manifest.permission#READ_PROFILE을 사용하면 개발자가 기기 사용자의 개인 식별 데이터에 액세스할 수 있게 해준다.



참고

특정 블로그에서만 찾은 자료가 아닌지라 출처는 생각나는 것만 남긴다.

http://www.javased.com/index.php?source_dir=android-client_1/src/com/googlecode/asmack/contacts/ContactDataMapper.java

안드로이드 연락처 초성검색 소스 : http://www.androidpub.com/45681

http://blog.mready.net/2012/09/android-contacts/ 에 나온 예제를 가지고 ContactHelper.java 클래스 파일을 만드는데 활용하면 좋을 거 같다.

블로그 이미지

Link2Me

,