droidtermsexample-release.zip


ContentProvier_BasicSetting.zip

ContentProvider_Completed.zip




** droidtermsexample apk파일을 다운로드 및 앱 실행 후, 코드를 작성해야 한다.


0. Result


     




1. Get permission to use the ContentProvider.


AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tistory.qlyh8.contentprovider">
 
    <!-- DroidTermsExample 컨텐트 프로바이더로부터 읽기 권한만 요청 -->
    <uses-permission android:name="com.example.udacity.droidtermsexample.TERMS_READ"/>
 
    <application
        ...
    </application>
cs




2. Using AsyncTask, Get the ContentResolver and 

   Identify the data you are manipulating to create a URI.


데이터베이스 작업은 오래 걸리는 작업이기 때문에,

메인 스레드가 아닌 다른 스레드에서 처리하기 위해 AsyncTask 이용한다.


2-1. Create an AsyncTask with the following generic types <Void, Void, Cursor>.

2-2. In the doInBackground method, 

      Write the code to access the DroidTermsExample provider and Return the Cursor object.

2-3. Create an instance variable Cursor mData and

      In the onPostExecute method, store the Cursor object in mData.

2-4. Create and execute the AsyncTask in onCreate.


MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package com.tistory.qlyh8.contentprovider;
 
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
import com.udacity.example.droidtermsprovider.DroidTermsExampleContract;
 
public class MainActivity extends AppCompatActivity {
 
    private int mCurrentState;  // 현재 상태
    private final int STATE_HIDDEN = 0// 단어 정의가 감줘져 있는 상태
    private final int STATE_SHOWN = 1;  // 단어 정의가 보여진 상태
 
    private Cursor mData;   // 컨텐트 프로바이더의 데이터
 
    private Button mButton;
    private TextView mWordTextView, mDefinitionTextView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        mButton = findViewById(R.id.button_next);
        mWordTextView = findViewById(R.id.text_view_word);
        mDefinitionTextView = findViewById(R.id.text_view_definition);
 
        // AsyncTask 를 생성하고 실행한다.
        new WordFetchTask().execute();
    }
 
    // 현재 단어 정의 보이기 / 다음 단어로 이동하기
    public void onButtonClick(View view) {...}
 
    // 현재 단어 정의 보이기
    public void showDefinition() {...}
 
    // 다음 단어로 이동하기
    public void nextWord() {...}
 
    public class WordFetchTask extends AsyncTask<Void, Void, Cursor>{
 
        @Override
        protected Cursor doInBackground(Void... voids) {
            // 컨텐트 리졸버를 가져온다.
            ContentResolver resolver = getContentResolver();
 
            // Contract 클래스로부터 리졸브의 쿼리 메서드를 호출한다.
            Cursor cursor = resolver.query(DroidTermsExampleContract.CONTENT_URI,
                    nullnullnullnull);
 
            return cursor;
        }
 
        @Override
        protected void onPostExecute(Cursor cursor) {
            super.onPostExecute(cursor);
            //MainActivity 를 위해 데이터를 세팅한다.
            mData = cursor;
            // 초기화
            nextWord();
        }
    }
}
 
cs




3. Display the information in the UI.


3-1. Get the column index, in the Cursor, of each piece of data.

3-2. Don't try to do showDefinition() and nextWord() if the cursor hasn't been set yet.

3-3Get the next word.

3-4. Close the cursor.


MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.tistory.qlyh8.contentprovider;
 
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
import com.udacity.example.droidtermsprovider.DroidTermsExampleContract;
 
public class MainActivity extends AppCompatActivity {
 
    private int mCurrentState;  // 현재 상태
    private final int STATE_HIDDEN = 0// 단어 정의가 감줘져 있는 상태
    private final int STATE_SHOWN = 1;  // 단어 정의가 보여진 상태
 
    private Cursor mData;   // 컨텐트 프로바이더의 데이터
    private int mDefCol, mWordCol;  // 커서의 단어 정의 및 단어 열 인덱스
 
    private Button mButton;
    private TextView mWordTextView, mDefinitionTextView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {...}
 
    // 현재 단어 정의 보이기 / 다음 단어로 이동하기
    public void onButtonClick(View view) {...}
 
    // 현재 단어 정의 보이기
    public void showDefinition() {
        if(mData != null){
            mButton.setText(getString(R.string.next_word));
            mDefinitionTextView.setVisibility(View.VISIBLE);
            mCurrentState = STATE_SHOWN;
        }
    }
 
    // 다음 단어로 이동하기
    public void nextWord() {
        if(mData != null) {
            // 커서의 다음 위치로 이동한다. 마지막 위치면 첫 번째 위치로 이동한다.
            if(!mData.moveToNext())
                mData.moveToFirst();
 
            mButton.setText(getString(R.string.show_definition));
            mDefinitionTextView.setVisibility(View.INVISIBLE);
 
            // 다음 단어를 가져온다.
            mWordTextView.setText(mData.getString(mWordCol));
            mDefinitionTextView.setText(mData.getString(mDefCol));
 
            mCurrentState = STATE_HIDDEN;
        }
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 커서를 닫는다.
        mData.close();
    }
 
    public class WordFetchTask extends AsyncTask<Void, Void, Cursor>{
 
        @Override
        protected Cursor doInBackground(Void... voids) {...}
 
        @Override
        protected void onPostExecute(Cursor cursor) {
            super.onPostExecute(cursor);
            //MainActivity 를 위해 데이터를 세팅한다.
            mData = cursor;
            // 각 데이터의 커서에서 열 인덱스를 가져온다.
            mDefCol = mData.getColumnIndex(DroidTermsExampleContract.COLUMN_DEFINITION);
            mWordCol = mData.getColumnIndex(DroidTermsExampleContract.COLUMN_WORD);
            // 초기화
            nextWord();
        }
    }
}
 
cs





Android Course of Udacity - Lesson 8

1. Get permission to use the ContentProvider.


컨텐트 프로바이더로부터 권한을 요청한다.

사용자에게 해당 앱이 실제로 어떤 일을 하는지 알려주는 권한 요청 시스템을 사용함으로써 사용자를 보호한다.


1
<uses-permission android:name="com.example.udacity.droidtermsexample.TERMS_READ"/>
cs




2. Get the ContentResolver.


컨텐트 프로바이더에 접근해 데이터를 가져온다.


사용자의 기기에는 다수의 컨텐트 프로바이더가 있기 때문에

어떤 컨텐트 프로바이더가 어떤 앱과 통신하는지 관리하고 모든 데이터의 동기화를 유지해야 하는데, 

이를 해결해주는 것이 컨텐트 리졸버이다.


컨텐트 리졸버는 각 앱과 앱이 접근하고자 하는 각 컨텐트 프로바이더 사이에서 중개자 역할을 한다.

이것은 프로세스 간의 통신을 처리해주고 모든 것을 동기화시켜주며 매끄럽게 작동하게 한다.


1
ContentResolver resolver = getContentResolver();
cs

컨텐트 리졸버를 받아온다.




3. Pick one of four basic actions on the data: query, insert, update, delete.


컨텐트 리졸버에서 4가지 기본 메서드 중 하나를 호출하면

컨텐트 리졸버는 컨텐트 프로바이더에게 해당 액션을 하라고 알려준다. 


query(): 데이터 읽기

insert(): 데이터에 행 추가

update(): 데이터 갱신

delete(): 데이터로부터 행 삭제


1
resolver.query(...);
cs




4. Identify the data you are reading or manipulating to create a URI and

   Read from the ContentProvider.


1
Cursor cursor = resolver.query(DroidTermsExampleContract.CONTENT_URI, nullnullnullnull);
cs

받아온 컨텐트 리졸버를 사용해 쿼리 메서드를 호출한다.



URI

URI는 데이터의 위치를 표시하고 데이터를 가져오기 위해 사용된다.


DroidTermsExampleContract.CONTENT_URI는 content://com.example.udacity.droidtermsexample/terms 를 의미한다.

(Content Provider Prefix)       (Content Authority)        (Specific Data)                       


이 URI는 안드로이드에서 컨텐트 프로바이더를 가리키기 위한 URIdroidtermsexample이라는 프로바이더에 있는

term에 접근하고자 함을 나타낸다.



query parameter

1
resolver.query(<URI><projection><selection><selection arguments><sort order>);
cs

 

projection : 칼럼을 필터링

selection : 행을 필터링하는 방법에 대한 설명 

selection arguments : 필터링 대상

sort order : 데이터의 정렬순서



Cursor

커서는 컨텐트 프로바이더의 데이터에 읽기/쓰기 접근을 제공하는 이터레이터(iterator)이다.


커서의 데이터는 테이블 형식이다.

커서에는 현재 가리키고 있는 로우를 나타내는 위치가 있는데, 처음 커서를 반환받았을 때 커서의 위치는 -1번째 행을 가리킨다.


주요 메서드

moveToNext() : 다음 행으로 이동하는 메서드. 이동 성공 여부에 따라 true/false 리턴

moveToFirst() : 첫 번째 행으로 위치를 움직이는 메서드

getColumnIndex(String heading) : 컬럼 헤딩을 넘겨 특정 칼럼의 인덱스를 가져오는 메서드.

get<Type>(int ColumnIndex) : 특정 칼럼 인덱스의 값을 리턴하는 메서드. <Type>: String, int, long etc.

getCount() : 커서 안의 행의 개수를 리턴하는 메서드.

close() : 메모리 누수를 방지하기 위해 커서를 닫는 메서드.





Android Course of Udacity - Lesson 8

Content Providers


컨텐트 프로바이더는 앱과 앱의 저장소 사이에서 데이터의 접근을 쉽게 관리할 수 있게 해주는 클래스이다.

컨텐트 프로바이더를 이용하면 간단하게 사용자 연락처, 문서, 또는 캘린더의 데이터를 가져오거나 추가할 수 있다.



Content Provider Advantages


컨텐트 프로바이더를 만드는 이유


1. Easily change underlying data source.

한 층의 추상화를 더함으로써

컨텐트 프로바이더를 접근하는 앱들의 코드 변경없이 개발자가 데이터 저장소에 변경을 줄 수 있다.


2. Leverage functionality of Android Classes.

로더나 커서어댑터 같은 몇몇 안드로이드 클래스들이 컨텐트 프로바이더를 사용한다.


3. Allow many apps to access, use, and modify a single data source securely.

개발자들이 접근하고, 사용하고, 수정할 수 있게 데이터 저장소를 열어두기 위함이다.



컨텐트 프로바이더 클래스에 코드를 추가함으로써 들어오는 데이터의 유효성을 검증하고 나가는 데이터를 보호할 수 있다.


개발자가 해야할 일은 앱의 권한 설정을 해주는 것과 코드 몇 줄을 추가하면 된다.





Android Course of Udacity - Lesson 8

+ Recent posts