BuildContentProvider_3.zip


* query 후 화면


 



데이터를 쿼리할 때는 비동기적으로 처리해줘야 하므로, 백그라운드 스레드에서 데이터를 가져와야 한다.

-> AsyncTask Loader 사용한다.


AsyncTask Loader

- onStartLoading(): 데이터를 로드하는 콜백 메서드를 구현한다.

- loadInBackground(): query를 백그라운드에서 수행한다.

- deliverResult(): 데이터를 반환한다.



Provider code


1. 할일 데이터베이스에 대한 읽기 액세스 권한을 얻는다.

   Get readable access to the underlying task database.

2. 할일 디렉토리와 디폴트를 인식하기 위해, match와 switch-case 코드를 작성한다.

   Write match code and a switch-case to recognize the task directory and default case.

3. 할일 디렉토리를 조회한다.

   Query for the tasks directory.

4. 커서에 알림 URI를 설정한다.

   Set a notification URI on the Cursor.


data/TaskContentProvider.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
85
86
87
88
89
90
91
92
93
94
package com.tistory.qlyh8.buildcontentprovider.data;
 
/*
 * Created by YUNHEE on 2018-01-09.
 */
 
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
 
import static com.tistory.qlyh8.buildcontentprovider.data.TaskContract.TaskEntry.TABLE_NAME;
 
public class TaskContentProvider extends ContentProvider {
 
    // 디렉토리일 경우 100, 200, 300 등으로 임의 지정한다.
    public static final int TASKS = 100;
    // 해당 디렉토리 안의 각 아이템일 경우 101, 102, 103 등으로 임의 지정한다.
    public static final int TASK_WITH_ID = 101;
 
    private static final UriMatcher sUriMatcher = buildUriMatcher();
    private TaskDbHelper mTaskDbHelper;
 
    // URI 를 상수값으로 매치 시켜주는 메서드
    public static UriMatcher buildUriMatcher() {...}
 
    // 데이터 소스를 설정하는 데 필요한 것을 초기화 해야한다.
    // 이 경우 SQLite 데이터베이스로 작업하기 때문에 DbHelper 를 초기화해야 액세스 할 수 있다.
    @Override
    public boolean onCreate() {...}
 
    // 요청된 데이터를 담고 있는 하나 이상의 로우에 대한 Cursor 객체를 반환하는 메서드.
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        final SQLiteDatabase db = mTaskDbHelper.getReadableDatabase();
        int match = sUriMatcher.match(uri);
        Cursor retCursor;
 
        switch (match){
            case TASKS:
                retCursor = db.query(TABLE_NAME, projection, selection, selectionArgs,
                        nullnull, sortOrder);
                break;
 
            case TASK_WITH_ID:
                // URI 로 부터 id를 가져온다. URI: content://<authority>/tasks/#
                // 인덱스 0번은 path 의 tasks 부분이며, 인덱스 1번은 바로 옆의 다음 부분이 된다.
                String id = uri.getPathSegments().get(1);
                
                String mSelection = "_id=?";
                String[] mSelectionArgs = new String[]{id};
                
                retCursor =  db.query(TABLE_NAME, projection, mSelection, mSelectionArgs,
                        nullnull, sortOrder);
                break;
 
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
 
        retCursor.setNotificationUri(getContext().getContentResolver(), uri);
 
        return retCursor;
    }
 
    // 반환될 내용의 MIME 타입을 반환하는 메서드. MIME 타입은 내용이 어떤 형식으로 되어있는지 식별한다.
    @Override
    public String getType(@NonNull Uri uri) {...}
 
    /**
     * 데이터 추가 메서드
     * @param uri: 데이터를 추가할 디렉토리를 알려주는 컨텐트 URI
     * @param values: 추가할 데이터를 담고있는 ContentValues 객체
     * @return 새로 추가된 데이터의 위치를 알려주는 컨텐트 URI, 실패시 -1
     */
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values) {...}
 
    // 데이터 삭제 메서드.
    // 어느 행을 삭제할 지 알려주는 URI 를 인자로 받아야 하며, 삭제된 행의 개수를 반환한다.
    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {...}
 
    // 데이터 갱신 메서드.
    // insert 의 인자들을 인자로 받아, 어느 URI 에 어떤 ContentValues 에 담긴 데이터로 갱신할 것인지 알 수 있다.
    // 갱신된 행의 개수를 반환환다.
    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {...}
}
 
cs



UI code


5. ContentResolver를 사용하여 모든 할일 데이터를 조회하고, 해당 데이터를 우선 순위별로 분류한다.

   Use a ContentResolver to query for all of the task data, and sort that data by priority.


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
package com.tistory.qlyh8.buildcontentprovider;
 
import android.annotation.SuppressLint;
import android.content.Intent;
import android.database.Cursor;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.View;
 
import com.tistory.qlyh8.buildcontentprovider.data.TaskContract;
 
public class MainActivity extends AppCompatActivity implements
        android.support.v4.app.LoaderManager.LoaderCallbacks<Cursor>{
 
    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int TASK_LOADER_ID = 0;
    private CustomCursorAdapter mAdapter;
 
    RecyclerView mRecyclerView;
    FloatingActionButton fabButton;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {...}
 
    // 일시중지되거나 재시작된 후에 메소드가 호출된다.
    // 보통 새로운 데이터가 AddTaskActivity 를 통해 삽입 된 후이다.
    // 이렇게하면 변경 사항에 대한 기본 데이터를 다시 쿼리하기 위해 로더가 다시 시작된다.
    @Override
    protected void onResume() {...}
 
    // 지정된 ID로 새로운 AsyncTaskLoader 를 인스턴스화하고 반환한다.
    // 이 로더는 작업 데이터를 커서 또는 오류가 발생하면 null 로 반환한다.
    // 로딩의 모든 단계에서 데이터 로딩을 처리하기 위해 필요한 콜백을 구현한다.
    @SuppressLint("StaticFieldLeak")
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new AsyncTaskLoader<Cursor>(this) {
 
            Cursor mTaskData = null;
 
            // 로더가 먼저 데이터를 로드할 때 호출된다.
            @Override
            protected void onStartLoading() {...}
 
            // 데이터의 비동기 로딩을 수행한다.
            @Override
            public Cursor loadInBackground() {
                try {
                    return getContentResolver().query(TaskContract.TaskEntry.CONTENT_URI,
                            nullnullnull,
                            TaskContract.TaskEntry.COLUMN_PRIORITY);
                } catch (Exception e){
                    Log.e(TAG, "Failed to asynchronously load data.");
                    e.printStackTrace();
                    return null;
                }
            }
 
            // 로드와 커서의 결과를 등록된 리스너에 보낸다.
            @Override
            public void deliverResult(Cursor data) {...}
        };
    }
 
    // 이전에 작성된 로더가 로드를 완료하면 호출된다.
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {...}
 
    // 이전에 작성된 로더가 재설정될 때 호출되어 해당 데이터를 사용할 수 없게 만든다.
    // 로더의 데이터에 대해 갖는 모든 참조를 제거한다.
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {...}
}
 
cs





Android Course of Udacity - Lesson 9

BuildContentProvider_2.zip


* insert 후 화면


 



4. URIMatcher를 생성한다.


URIMatcher는 컨텐트 프로바이더가 받은 URI의 종류를 결정하고, 프로바이더를 정수값의 상수로 매칭시킨다.


4-1. Define final integer constants for multiple and single rows of data.

4-2. Declare a static global variable for the complete UriMatcher

4-3. Define a buildUriMatcher method that associates URI's with their int match


data/TaskContentProvider.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
package com.tistory.qlyh8.buildcontentprovider.data;
 
/*
 * Created by YUNHEE on 2018-01-09.
 */
 
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
 
public class TaskContentProvider extends ContentProvider {
 
    // 디렉토리일 경우 100, 200, 300 등으로 임의 지정한다.
    public static final int TASKS = 100;
    // 해당 디렉토리 안의 각 아이템일 경우 101, 102, 103 등으로 임의 지정한다.
    public static final int TASK_WITH_ID = 101;
 
    private static final UriMatcher sUriMatcher = buildUriMatcher();
    private TaskDbHelper mTaskDbHelper;
    
    // URI 를 상수값으로 매치 시켜주는 메서드
    public static UriMatcher buildUriMatcher() {
        // UriMatcher.NO_MATCH 상수를 넘겨 빈 매처를 만든다.
        UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        /*
         * addURI(String authority, String path, int code)
         * 첫 번째와 두 번째 인자는 합쳐져, 인식하고자 하는 URI 를 매처에게 알려준다.
         * 세번째 인자를 사용해 해당 URI 를 어느 상수에 매칭시킬지 설정한다.
         */
        // 할일 디렉토리의 모든 행을 나타내는 URI
        uriMatcher.addURI(TaskContract.AUTHORITY, TaskContract.PATH_TASKS, TASKS);
        // 하나의 할일을 나타내는 URI
        uriMatcher.addURI(TaskContract.AUTHORITY, TaskContract.PATH_TASKS + "/#", TASK_WITH_ID);
 
        return uriMatcher;
    }
 
    @Override
    public boolean onCreate() {...}
 
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {...}
 
    @Override
    public String getType(@NonNull Uri uri) {...}
 
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values) {...}
 
    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {...}
 
    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {...}
}
 
cs



** UI 코드에서 데이터베이스에 작업을 호출하는 과정


UI - Resolver(URI) - Provider - URIMatcher - SQL Code - Database


a. UI 코드에서 Content Resolver를 가져와 쿼리 메소드를 호출하고, 

b. 특정 프로바이더와 읽고자 하는 데이터를 나타내는 URI를 같이 넘겨준다.

c. 리졸버는 넘겨진 URI의 authority에 따라 올바른 TaskContentProvider를 찾아서 쿼리를 전달한다.

d. 쿼리 함수는 URIMatcher를 사용해 어떤 데이터를 가져와야 하는지 (전체/하나) 결정한다.

e. 쿼리 함수는 선택된 데이터에 대해 알맞은 SQL code를 생성한다.

f. 프로바이더는 database에서 대상 데이터가 담긴 커서를 반환한다.



5. 데이터에 추가하기 위해 insert 메서드를 구현한다.


5-1. Get Writeable access to the task database.

5-2. Write URIMatching code to recognize the match for the tasks directory.

5-3. Write code to insert a row of data into the existing directory.

5-4. Set the value for the returned URI and write the default case.

5-5. Notify the ContentResolver if the URI has changed.


data/TaskContentProvider.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
85
86
87
88
89
90
91
92
package com.tistory.qlyh8.buildcontentprovider.data;
 
/*
 * Created by YUNHEE on 2018-01-09.
 */
 
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
 
public class TaskContentProvider extends ContentProvider {
 
    // 디렉토리일 경우 100, 200, 300 등으로 임의 지정한다.
    public static final int TASKS = 100;
    // 해당 디렉토리 안의 각 아이템일 경우 101, 102, 103 등으로 임의 지정한다.
    public static final int TASK_WITH_ID = 101;
 
    private static final UriMatcher sUriMatcher = buildUriMatcher();
    private TaskDbHelper mTaskDbHelper;
 
    // URI 를 상수값으로 매치 시켜주는 메서드
    public static UriMatcher buildUriMatcher() {...}
 
    // 데이터 소스를 설정하는 데 필요한 것을 초기화 해야한다.
    // 이 경우 SQLite 데이터베이스로 작업하기 때문에 DbHelper 를 초기화해야 액세스 할 수 있다.
    @Override
    public boolean onCreate() {...}
 
    // 요청된 데이터를 담고 있는 하나 이상의 로우에 대한 Cursor 객체를 반환하는 메서드.
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {...}
 
    // 반환될 내용의 MIME 타입을 반환하는 메서드. MIME 타입은 내용이 어떤 형식으로 되어있는지 식별한다.
    @Override
    public String getType(@NonNull Uri uri) {...}
 
    /**
     * 데이터 추가 메서드
     * @param uri: 데이터를 추가할 디렉토리를 알려주는 컨텐트 URI
     * @param values: 추가할 데이터를 담고있는 ContentValues 객체
     * @return 새로 추가된 데이터의 위치를 알려주는 컨텐트 URI, 실패시 -1
     */
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values) {
 
        Uri returnUri;
 
        // 새 데이터를 쓰기 위해 데이터베이스에 접근한다.
        final SQLiteDatabase db = mTaskDbHelper.getWritableDatabase();
        // 할일 디렉토리에 매칭되는 URI 매칭 코드를 받는다.
        int match = sUriMatcher.match(uri);
 
        switch (match){
            case TASKS:
                // 테이블에 추가한다.
                long id = db.insert(TaskContract.TaskEntry.TABLE_NAME, null, values);
                if(id > 0){
                    // insert 성공
                    // ContentUris 는 URI 를 쉽게 만들 수 있게 도와주는 메서드를 담고있는 헬퍼 클래스
                    // withAppendId(): 첫 번째 인자를 베이스로 URI 를 만들고 두 번째 인자로 들어온 id를 path 의 마지막에 덧붙인다.
                    returnUri = ContentUris.withAppendedId(TaskContract.TaskEntry.CONTENT_URI, id);
                } else {
                    // insert 실패
                    throw new android.database.SQLException("Failed to insert row into " + uri);
                }
                break;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        // 컨텐트 리졸버에게 특정 URI 에 변경사항이 생겼다고 알린다.
        getContext().getContentResolver().notifyChange(uri,null);
 
        return returnUri;
    }
 
    // 데이터 삭제 메서드.
    // 어느 행을 삭제할 지 알려주는 URI 를 인자로 받아야 하며, 삭제된 행의 개수를 반환한다.
    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {...}
 
    // 데이터 갱신 메서드.
    // insert 의 인자들을 인자로 받아, 어느 URI 에 어떤 ContentValues 에 담긴 데이터로 갱신할 것인지 알 수 있다.
    // 갱신된 행의 개수를 반환환다.
    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {...}
}
 
cs



5-6. Put the text description and priority into a ContentValues object.

5-7. Use a ContentResolver to insert these values into the tasks directory.

5-8. Include a Toast to view the inserted content URI.


AddTaskActivity.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
package com.tistory.qlyh8.buildcontentprovider;
 
/*
 * Created by YUNHEE on 2018-01-09.
 */
 
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Toast;
 
import com.tistory.qlyh8.buildcontentprovider.data.TaskContract;
 
public class AddTaskActivity extends AppCompatActivity{
 
    private int mPriority;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {...}
 
    // 우선순위 버튼을 눌렀을 때 호출된다.
    // 선택한 버튼을 기준으로 mPriority 의 값이 변경된다.
    public void onPrioritySelected(View view) {...}
 
    // "ADD" 버튼을 눌렀을 때 호출된다.
    // 사용자 입력을 얻어 새 할일 데이터를 기본 데이터베이스에 삽입한다.
    public void onClickAddTask(View view) {
        String input = ((EditText) findViewById(R.id.editTextTaskDescription)).getText().toString();
        if (input.length() == 0) {
            return;
        }
 
        // 할 일 데이터를 담을 새로운 ContentValue 객체 생성한다.
        ContentValues contentValues = new ContentValues();
        // 할일과 우선순위의 key 와 value 를 각각 넣는다.
        contentValues.put(TaskContract.TaskEntry.COLUMN_DESCRIPTION, input);
        contentValues.put(TaskContract.TaskEntry.COLUMN_PRIORITY, mPriority);
 
        // 컨텐트 리졸버를 호출해 데이터베이스에 추가하고
        // 할 일 디렉터리에 접근하기 위한 올바른 컨텐트 URI 를 넘겨준다.
        Uri uri = getContentResolver().insert(TaskContract.TaskEntry.CONTENT_URI, contentValues);
 
        if(uri != null){
            Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show();
        }
 
        // 메인 액티비티로 돌아간다.
        finish();
    }
}
 
cs





Android Course of Udacity - Lesson 9

BuildContentProvider_BasicSetting.zip

BuildContentProvider_1.zip



0. Result (커스텀 컨텐트 프로바이더를 적용하기 전 화면)


 




1. Android SDK에서 제공하는 ContentProvider 추상 클래스를 상속받는 새로운 프로바이더 클래스를 만든다.


안드로이드의 컨텐트 프로바이더를 상속받음으로써 해당 클래스가 유효한 프로바이더로 인식될 수 있다.

onCreate 메서드에 데이터 소스를 설정하는 데 필요한 초기화 코드를 작성한다.


data/TaskContentProivider.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
package com.tistory.qlyh8.buildcontentprovider.data;
 
/*
 * Created by YUNHEE on 2018-01-09.
 */
 
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
 
public class TaskContentProvider extends ContentProvider {
 
    private TaskDbHelper mTaskDbHelper;
 
    // 데이터 소스를 설정하는 데 필요한 것을 초기화 해야한다.
    // 이 경우 SQLite 데이터베이스로 작업하기 때문에 DbHelper 를 초기화해야 액세스 할 수 있다.
    @Override
    public boolean onCreate() {
        mTaskDbHelper = new TaskDbHelper(getContext());
        return true;
    }
 
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {...}
 
    @Override
    public String getType(@NonNull Uri uri) {...}
 
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values) {...}
 
    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {...}
 
    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {...}
}
 
cs




2. AndroidManifest에서 새로운 프로바이더(TaskContentProvider)를 등록한다.


매니페스트에 등록됨으로써 프로바이더는 시스템에 보이게 되고 앱으로부터 참조될 수 있게 된다.

또한 UI 코드에서 컨텐트 리졸버를 사용해 해당 프로바이더를 호출하게 되었을 때 이 호출을 넘겨줄 수 있다.


AndroidManifest.xml

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
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tistory.qlyh8.buildcontentprovider">
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            ...
        </activity>
 
        <activity android:name=".AddTaskActivity"
            android:label="@string/add_task_activity_name"/>
 
        <!-- exported: 컨텐트 프로바이더에 다른 앱이 접근할 수 있을지를 결정한다. -->
        <provider
            android:authorities="com.tistory.qlyh8.buildcontentprovider"
            android:name=".data.TaskContentProvider"
            android:exported="false"/>
 
    </application>
 
</manifest>
cs




3. Contract 클래스의 URI을 추가한다.


URI는 컨텐트 리졸버에게 어떤 프로바이더와 통신할 것인지 그리고 요청하는 특정 데이터가 무엇인지 알려준다.

나중에 컨텐트 리졸버는 해당 프로바이더를 찾을 수 있고, 주어진 URI만으로 특정 데이터를 접근할 수 있다.


URI 예) content://com.android.todolist/tasks/2 : task에서 2라는 id를 가진 행

    (scheme)  (       authority      ) ( path )


Wildcard characters

"path" : "path"경로에 매치

"path/#" : "path" 다음에 길이와 상관없이 모든 정수와 매치 (# = 1,2,3)

"path/*" : "path" 다음에 길이와 상관없이 모든 문자열과 매치 (* = description, priority)

"path/*/other/#" : "path" 다음에 문자열이 오고, "other" 뒤에 정수가 매치


data/TaskContract.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
package com.tistory.qlyh8.buildcontentprovider.data;
 
/*
 * Created by YUNHEE on 2018-01-09.
 */
 
import android.net.Uri;
import android.provider.BaseColumns;
 
public class TaskContract {
 
    // 해당 데이터의 경로에 컨텐츠 URI 를 제공
    public static final String AUTHORITY = "com.tistory.qlyh8.buildcontentprovider";
    public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + AUTHORITY);
    public static final String PATH_TASKS = "tasks";
 
    // BaseColumns 인터페이스로 인해 자동으로 "_ID" 칼럼이 생성된다.
    public static final class TaskEntry implements BaseColumns {
 
        // 자주 사용하는 URI 형식을 참조하는 것을 돕는다.
        public static final Uri CONTENT_URI =
                BASE_CONTENT_URI.buildUpon().appendPath(PATH_TASKS).build();
 
        public static final String TABLE_NAME = "tasks";
 
        public static final String COLUMN_DESCRIPTION = "description";
        public static final String COLUMN_PRIORITY = "priority";
    }
}
 
cs





Android Course of Udacity - Lesson 9

+ Recent posts