일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Apollo Server
- ubuntu python
- 파이썬 크롤링
- Android
- 안드로이드 mvp
- 안드로이드 테스트
- mvvm
- Apollo GraphQL
- MVVM pattern
- 자바
- prisma
- flutter
- dagger-hilt
- 자바기초
- 안드로이드 디자인패턴
- 우분투 파이썬
- unit test
- 유니티
- LinkedList
- Design Pattern
- Dependency Injection
- 웹크롤링
- java
- 안드로이드
- Nexus GraphQL
- PYTHON
- graphQL
- Data structure
- Android test
- Kotlin
- Today
- Total
Hun's Blog
[Android] 안드로이드 4대 컴포넌트 - Content Provider 본문
Content Provider
컨텐트 프로바이더는 어플리케이션 사이에서 데이터를 공유하는 통로 역할을 한다. 각종 설정값이나 DB에 접근하게 해 주며 결과를 반환하는 브릿지 역할은 컨텐트 리졸버(Content Resolver)가 한다. 컨텐트 리졸버는 컨텐트 프로바이더의 주소를 통해 데이터에 접근하여 결과를 가져온다.
App -ContentUri-> ContentResolver --> ContentProvider -->DBClass -->SQLite
안드로이드 시스템에서는 각 어플리케이션마다 각각의 DB를 가질 수 있다. 그리고 어플리케이션 내부의 DB는 해당 어플리케이션만 접근이 가능하다. 다른 어플리케이션에게 DB가 전부 공개된다면 보안에 취약해 질 수 있기 때문이다. 하지만, 어플리케이션 DB 접근을 완전히 막는 것도 문제가 될 수 있다. 어플리케이션 사이에 데이터를 공유할 수 없게되기 때문이다. 카카오톡 프로필사진을 변경하고 싶은데 카카오톡이 나의 갤러리 어플리케이션 DB에 접근할 수 없다면 프로필 사진을 업로드 할 수 없다.
*안드로이드 시스템은 어플리케이션 내부 DB에 대해 해당 어플리케이션만 접근 가능한 보안성과 다른 어플리케이션에서도 DB에 접근할 수 있도록 유연함을 제공하기 위해 컨텐트 프로바이더 클래스를 제공하는 것이다.
다시 정리해보면
외부 앱이 특정 앱의 DB 정보가 필요한 경우, 외부 앱은 컨텐트 리졸브를 통해 Uri를 해당 앱에 보내고, 해당 앱의 컨텐트 프로바이더가 Uri를 해석하여 필요한 DB작업을 하게 된다. 이때, Uri를 전달받은 컨텐트 프로바이더는 기본적은 CRUD 연산을 모두 처리 가능하다. 컨텐트 프로바이더는 필요한 작업을 모두 수행하고, 결과값을 컨텐트 리졸브에 반환한다.
*컨텐트 프로바이더와 컨텐트 리졸브를 통해 앱과 앱 사이에 데이터베이스를 공유하면서 직접적인 접근을 차단할 수 있다.
*안드로이드는 android.provider 패키지에 콘텐트 프로바이더가 나열되어있다.
- 연락처
- 전화기록
- 오디오
- 비디오
...
Content Resolver 객체
ContentResolver 객체는 getContentResolver()를 통해 얻을 수 있다. ContentResolver 객체의 메소드를 통해 데이터를 생성, 검색, 업데이트, 삭제 등을 할 수 있다. 마치 데이터베이스에서 query를 하듯 ContentResolver 객체의 query() 메소드가 컨텐트 프로바이더로 부터 데이터와 관련된 작업을 하게된다.
https://choidev-1.tistory.com/56
해당링크의 학생DB 예제를 통해 콘텐트 프로바인더를 알아 보도록 하겠다. 이외의 자세한 설명은 해당 블로그에 자세히 정리되어있다.
예제
SQLite에 특정 학생의 정보를 추가하고 수정하고 삭제하고 쿼리를 확인한다.
콘텐트 프로바이더 인터페이스를 활용해서 해당 기능들을 구현한 예제이다.
SQLite
db 를 생성한 앱 내부에서만 접근 가능한 데이터 베이스이다.
때문에 외부의 앱에서 접근하기 위해서는 콘텐트 프로바이더가 필요하다.
매니페스트 파일 설정
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
해당 앱이 외부 저장소에 접근하여 읽고 수정할 수 있는 권한을 부여한다.
특정 정보를 저장하게 되면 오직 해당 앱에서만 그 데이터를 다룰 수 있다.
1
2
3
4
|
<provider
android:name=".StudentProvider"
android:authorities="com.jroomstudio.myapplication.StudentProvider"
android:exported="true"></provider>
|
StudentProvider 클래스는 ContentProvider를 상속받으므로 외부에서 해당 클래스로 접근하면 데이터베이스에 접근 할 수 있게된다.
StudentProvider 클래스의 프로젝트상 저장위치가 Uri처럼 사용된다.
1. db 생성 클래스 - StudentDBManager.java
1
2
3
4
5
|
static final String TABLE_STUDENT = "Students";
static final int DB_VERSION = 2;
Context context = null;
private static StudentDBManager dbManager = null;
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
SQLiteOpenHelper를 상속받아 저장할 데이터베이스를 생성하는 클래스이다.
데이터베이스에 대한 자세한 내용은 다루지 않겠다.
2. db에 접근하는 프로바이더 클래스 - StudentProvider.java
public StudentDBManager dbManager = null;
위에서 생성한 데이터베이스와 외부 앱사이에서 데이터의 흐름을 관리하는 콘텐트 프로바이더 클래스이다.
데이터베이스 객체 생성
1
2
3
4
5
|
@Override
public boolean onCreate() {
dbManager = StudentDBManager.getInstance(getContext());
return true;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
insertAll
1
2
3
4
|
@Override
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
return dbManager.insertAll(values);
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
query
1
2
3
4
5
|
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
delete
1
2
3
4
|
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
insert
1
2
3
4
5
|
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
update
1
2
3
4
5
|
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
CRUD 의 기능이 구현되어있다. 이 프로바이더 클래스가 위에서 생성한 SQLite 데이터베이스와 연결되어 관리되기 때문에 외부앱은 해당 클래스를 찾아올 수 있는 Uri를 타고 들어와 해당 앱의 주인이 지정해 놓은 권한에 따라 데이터베이스에 접근하여 데이터를 다룰 수 있게 되는 것이다.
3. MainActivity.java -- onClick 메소드
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
|
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_insert: {
ContentValues addRowValue = new ContentValues();
getContentResolver().insert(Uri.parse(PROVIDER_URI),addRowValue);
editText.setText("recode add");
break;
}
case R.id.btn_query:{
String[] columns = new String[]{"_id","number","name","department","age","grade"};
Cursor c = getContentResolver().query(
columns,null,null,null,null);
if(c != null){
editText.setText("");
while (c.moveToNext()){
int id = c.getInt(0);
String number = c.getString(1);
String name = c.getString(2);
String department = c.getString(3);
String age = c.getString(4);
int grade = c.getInt(5);
"id : "+id+"\n"
+"number : "+number+"\n"
+"name : "+name+"\n"
+"department : "+department+"\n"
+"age : "+age+"\n"
+"grade : "+grade+"\n");
}
c.close();
}
break;
}
case R.id.btn_update:{
ContentValues updateRowValue = new ContentValues();
int updateRecordCnt = getContentResolver().update(
updateRowValue,
"number=200106504",null);
editText.setText("갱신 : " + updateRecordCnt);
break;
}
case R.id.btn_delete:{
int deleteRecordCnt = getContentResolver().delete(
editText.setText("삭제 : " + deleteRecordCnt);
break;
}
}
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs |
데이터베이스 접근을 위해 getContentResolver() 가 반복적으로 사용되는 것을 기억해두자.
정리 -
대부분의 앱들은 필요에 따라 로컬 데이터베이스를 구현하여 디바이스 내부의 저장소를 활용한다. 사진 앱으로 사진을 찍고 갤러리라는 앱에 저장되는 것도 내부 저장소를 활용한 것이다. 디바이스에 설치된 수많은 앱들이 각각의 데이터베이스 메모리를 할당받아서 사용하는데 안드로이드에선 특정 앱에서 할당받아 사용하는 데이터베이스에 대해서 다른앱이 접근하지 못하도록 철저하게 관리한다.
생각해보자. 식단관리 앱을 깔고 나의 신체정보와 식사기록들을 저장하여 사용하고 있었다. 어느날 뜬금없이 페이스북에서 "오늘 많이드셨네요? 친구들에게 알려서 반성좀하세요" 라는 알림메세지가 왔다. 상상도 할 수 없는일이다. 만약 안드로이드에서 앱의 로컬데이터베이스에 대하여 관대하다면 저런일이 일어 날 수 있게된다.
하지만 너무 막아두는것도 문제가 되는것이 페이스북 프로필을 변경하려 갤러리앱으로 들어가려하는데 "접근불가 - 페이스북에서 직접 찍어서 올리세요" 라는 경고창이 뜬다고 생각해보자. 이 또한 말도 안되는 일이다.
이러한 문제를 적절히 해결하는 컴포넌트가 콘탠트 프로바이더 이다.
내가만든 앱에 데이터를 다른 앱에서도 접근해서 사용하도록 하고싶다.
1. 데이터 베이스를 만들어 데이터를 저장한다.
2. 콘탠트 프로바이더클래스를 생성한다.
3. 프로바이더 클래스로 찾아올 수 있도록 uri도 알려준다.
4. 콘탠트 리졸브를 생성하여 crud 기능을 구현한다.
A(APP)라는 사람이 큰 창고(데이터베이스)를 가지고 있는데 식량(데이터)을 많이 비축해 두었다. 몇 개의 식량은 마을주민( 다른 APP)들에게 나눠주고 싶다. 그냥 창고문을 개방하자니 값비싼 식량들이 많아서 불안하다. 그래서 관리인(리졸브) 을 고용하고 창구(프로바이더) 를 만들어서 필요한 주민(다른APP)이 찾아가도록 하였다.
- 주민들은 창고에 직접 들어갈 수 없고 창구로 찾아가 관리 인에게 요청을한다.
- 관리인은 창구에서 정해진 규칙에 따라서 물건을 가져다 준다.
참고
https://choidev-1.tistory.com/56
https://bitsoul.tistory.com/155
https://salix97.tistory.com/11
https://mainia.tistory.com/4924
https://developer.android.com/guide/topics/providers/content-provider-basics?hl=ko
'Android' 카테고리의 다른 글
[Android] Android Test 2 - Unit Test (JUnit) (0) | 2020.03.22 |
---|---|
[Android] Android Test 1 - Android Test란 무엇인가? (0) | 2020.03.22 |
[Android] 안드로이드 4대 컴포넌트 - Broadcast Receiver (0) | 2020.03.21 |
[Android] 안드로이드 4대 컴포넌트 - Service (0) | 2020.03.21 |
[Android] 안드로이드 4대 컴포넌트 - Activity (0) | 2020.03.21 |