안드로이드 : 컨텐트 제공자 (Content Provider) 예제 - 연락처 데이터


안드로이드 4대 컴포넌트 중 하나인

콘텐트 제공자 (Content Provider) 는  어플리케이션 내에서 사용할수 있는 데이터를 '공유'하기 위한 컴포넌트 이며 아래 그림과 같이, '어플리케이션 계층(Business Layer)'와 '데이터 계층(Data Layer)'를 분리하여 중간 가교 역할을 합니다.




어플리케이션은 콘텐트 제공자 (Content Provider) 에만 접근하면 필요한 데이터를 얻어올수 있는 겁니다.

그래서, 혹자는  콘텐트 제공자 (Content Provider)가 서버와 비슷한 역할을 한다고 합니다

다양한 데이터들을 저장하고 있다가, 어플리케이션의 요청이 들어오면 데이터를 제공하게 되니까요.


만약 다른 어플리케이션과 공유할 필요가 없는데이터라면

콘텐트 제공자 가 아닌 자체적으로 저장하고 관리하면 됩니다.


복습차원에서 일전에 어플리케이션에서 자료를

저장하는 4가지 방법에 대해 포스팅드렸기에 링크 드립니다

1. InternalStorage 장치내부 파일 생성 / 읽기 예제

2. ExternalStorage 외부저장장치 파일 생성 / 읽기 예제

3. SQLite3 사용예제2   SQLite3 사용예제1

4. Shared Preferences 사용예제

자! 그럼 어떠한 자료들이 '공유'할 만한 자료일까요?

대표적으로 '연락처' 이 있겠죠.  카카오톡 이나 수많은 SNS 관련 앱들이 주소록 정보를 활용하여 친구 찾기 기능등에 활용하고 있죠

안드로이드는 android.provider ,패키지에 콘텐트 제공자 (Content Provicer) 가 나열되어 있습니다. (연락처, 전화기록 , 오디오, 비디오....)

따라서, 콘텐트 제공자 (Content Provicer)  데이터를 사용하려면 권한 획득도 필요하겠죠.


ContentResolver 객체

ContentResolver 객체가 콘텐트 제공자 (Content Provider) 이며  getContentResolver() 를 통해 얻을수 있습니다.
ContentResolver 객체의 메소드를 통해 데이터를 생성, 검색, 업데이트, 삭제 등을 할수 있습니다.   이때 ContentResolver 객체와 ContentProvider ,객체는 서로 다른 프로세스간 통신으로 데이터를 주고 받습니다.



마치 데이터베이스 에서 query 를 하듯히 ContentResolver 객체의 query() 메소드가 ContentProvider 로부터 데이터 관련죈 작업을 하게됩니다.     


자꾸 서론이 길어지는것 같은데,  더 세부적인것은 훗날의 포스팅에 기대(?) 해보고, 곧바로 '연락처' 데이터를 콘텐트 제공자 (Content Provider) 로부터 받아서 출력해보는 예제를 보여드리겠습니다


[메니페스트 ,AndroidManifest.xml] 

연락처 접근 권한 얻기.  아래 두 줄을 추가해 줍니다


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="bitsoul.com.a108contentprovider">

<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>


[레이아웃 준비 activity_main.xml]


ScrollView 로 준비해보겠습니다 (주소록이 많을수 있으니)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ContentProvider 활용\n주소록 읽어오기"
android:textAppearance="?android:attr/textAppearanceLarge" />

<ScrollView
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="전화번호부 검색결과"
android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>
</ScrollView>

</LinearLayout>




[MainActivity.java]

액티비티 작성.  마치 데이터베이스에 쿼리문 실행하고 레코드세트를 받아오듯이 ContentResolver 객체의 query() 메소드로 콘텐트 제공자 (Content Provicer) 로부터 데이터 세트를 받아옵니다.  이를 다루기 위해 Cursot 객체가 쓰여지고 있고, moveToFirst(), moveToNext() 메소드로 데이터 세트를 하나하나 뽑아냅니다.   

여기서 query() 메소드에 넘겨주는 매개변수들은 데이터 형태등에 따라 달라집니다.  첫번째 매개변수가 콘텐트 URI 인에 콘텐트 제공자 안에 있는 테이블을 가리키는 URI 입니다.  (지금은 주소록을 접근하기 위해 ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME 값을 사용했습니다.


import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.TextView;

public class MainActivity extends Activity {

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

// 컨텐트 프로바이더 (ContentProvider)
// 어플리케이션 내에서만 사용할 수 있는 데이터를 공유하기위한
// 방법으로 안드로이드의 4대 컴포넌트 중 하나이다

// 폰에 저장되있는 전화번호부를 읽어보기(권한 필요)
// AndroidManifest.xml

TextView tv = (TextView)findViewById(R.id.textView2);

Cursor c = getContentResolver().query(
ContactsContract.CommonDataKinds
.Phone.CONTENT_URI, // 조회할 컬럼명
null, // 조회할 컬럼명
null, // 조건 절
null, // 조건절의 파라미터
null);// 정렬 방향

String str = ""; // 출력할 내용을 저장할 변수
c.moveToFirst(); // 커서를 처음위치로 이동시킴
do {
String name = c.getString
(c.getColumnIndex(ContactsContract
.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = c.getString
(c.getColumnIndex(ContactsContract
.CommonDataKinds.Phone.NUMBER));
str += "이름 : " + name
+"폰번호 : " + phoneNumber + "\n";
} while (c.moveToNext());//데이터가 없을 때까지반복
tv.setText(str);
} // end of onCreate
} // end of class



[실행결과]




ContentProvider 는 다양한 형태의 데이터를 담고 있고 그에따라 query() 해야 하는 방법이나, 추출한 데이터를 다루는 방법이 다릅니다.  기회가 닿는대로 하나하나 다루어 볼수 있도록 하겠습니다.