ContentProvider 기능이 필요해서 가져다 사용 하려는데,

현재 검색되는 코드들은 대부분 되는 것들이 없어서 (코드 자체로는 전혀 문제가 없었지만 추가사항이 있어서..) 코드 공유 합니다.


기본적인 설명으로는 여기를 

https://developer.android.com/guide/topics/providers/content-provider-creating.html?hl=ko


이외 코드 관련 부분은 아래에서 참고하였습니다.

참고URL : https://www.tutorialspoint.com/android/android_content_providers.htm



주의사항!

studio가 불안정한건지, 아님 저의 툴 설정이 문제인건지, 여러번 빌드시 이전 provider 설정들이 남아 있는건지

정상 동작하지 않던 문제가 있었습니다. 

저같은 경우는 항상 A,B 앱을 uninstall 후에 빌드 시 제대로된 결과을 얻을 수 있었습니다.

(Permission Denial: opening provider com.app.first.myContentProvider from ..... 등등이 나온다면...)



1. A앱 작업 Mainfests (퍼미션을 추가합니다. 프로바이더 내에서도 readPermission과 writePermission , exprted를 명시합니다.)

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.app.first">     <!-- 퍼미션 추가 --> <permission android:name="com.app.first.READ_DATABASE" android:protectionLevel="normal" /> <permission android:name="com.app.first.WRITE_DATABASE" android:protectionLevel="normal" /> <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" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- 프로바이더 등록 --> <provider android:name=".myContentProvider" android:authorities="com.app.first.myContentProvider" android:exported="true" android:readPermission="com.app.first.READ_DATABASE" android:writePermission="com.app.first.WRITE_DATABASE"/> </application> </manifest>

activity_main.xml (레이아웃 만들기)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context="com.app.first.MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="데이터 불러오기"
        android:id="@+id/bt_renew"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_below="@id/bt_renew"
        android:textSize="15sp"
        android:text="Hello World!"
        android:id="@+id/tv_text"/>

</RelativeLayout>

MainActivity.java (메인 화면 처리)

package com.app.first;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    DBHelper mDatabase;

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

        mDatabase = new DBHelper(getBaseContext());

        // 데이터 입력
        mDatabase.setDelete();
        List<ItemRow> mList = new ArrayList<>();
        mList.add(new ItemRow("식사","미역국",5000));
        mList.add(new ItemRow("간식","우유",4000));
        mList.add(new ItemRow("간식","바나나",3000));
        mList.add(new ItemRow("식사","오이",2000));
        mList.add(new ItemRow("식사","당근",1000));
        for(ItemRow item : mList) {
            mDatabase.setItem(item.contents, item.name, item.num);
        }

        Button bt_renew = (Button) findViewById(R.id.bt_renew);
        bt_renew.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 데이터 불러오기
                loadData();
            }
        });
    }

    private void loadData() {
        StringBuilder sb = new StringBuilder();
        List<ItemRow> row = mDatabase.getItem();
        sb.append("Total count : "+row.size()+"\n\n");
        for(ItemRow item : row) {
            sb.append(item.contents+" , "+item.name+" , "+item.num+"\n");
        }
        TextView tv_text = (TextView) findViewById(R.id.tv_text);
        tv_text.setText(sb.toString());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mDatabase != null)
            mDatabase.close();
    }
}

class ItemRow {
    public String contents;
    public String name;
    public int num;

    public ItemRow(String contents, String name, int num) {
        this.contents = contents;
        this.name = name;
        this.num = num;
    }
}

DBHelper.java (디비 로직 작업)

package com.app.first;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;

import java.util.ArrayList;
import java.util.List;

public class DBHelper extends SQLiteOpenHelper {

    private static final int db_version = 1;					// Database Version
    private static final String DB_FILE_NAME = "UserData.db";

    private static final String [] COLUMNS = {"contents TEXT", "name TEXT", "num INTEGER"};
    public static String TABLE_NAME = "my_table";

    public DBHelper(Context context) {
        // TODO  http://stackoverflow.com/questions/4547461/closing-the-database-in-a-contentprovider
        super(context, DB_FILE_NAME, null, db_version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table " + TABLE_NAME +
                " (" + BaseColumns._ID + " integer primary key autoincrement ";
        for (int i = 0; i < COLUMNS.length; i++) {
            sql += ", " + COLUMNS[i];
        }
        sql += " ) ";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

    public List<ItemRow> getItem() {
        List<ItemRow> list = new ArrayList<>();
        try {
            beginTransaction();
            Cursor c = getAll(TABLE_NAME);
            if (c != null) {
                int total = c.getCount();
                if (total > 0) {
                    c.moveToFirst();
                    while (!c.isAfterLast()) {
                        String contents = c.getString(1);
                        String name = c.getString(2);
                        int num = c.getInt(3);
                        list.add(new ItemRow(contents, name, num));
                        c.moveToNext();
                    }
                }
                c.close();
            }
        } catch (SQLiteException e) {
            e.printStackTrace();
        } finally {
            endTransaction();
        }
        return list;
    }

    public void setItem(String contents, String name, int num) throws SQLiteException{
        ContentValues values = new ContentValues();
        values.put("contents", contents);
        values.put("name", name);
        values.put("num", num);
        insert(TABLE_NAME, values);
    }

    public void setDelete() {
        AllDelete(TABLE_NAME);
    }

    protected Cursor getAll(String tableName) throws SQLiteException {
        return getReadableDatabase().query(tableName, null, null, null, null, null, /*"date desc"*/null);
    }

    protected void beginTransaction() {
        getWritableDatabase().beginTransaction();
    }
    protected void endTransaction() {
        getWritableDatabase().setTransactionSuccessful();   // db 속도 향상
        getWritableDatabase().endTransaction();
    }

    protected void insert(String tableName, ContentValues values) throws SQLiteException {
        getWritableDatabase().insert(tableName, null, values);
    }

    protected void AllDelete(String tableName) throws SQLiteException{
        getWritableDatabase().delete(tableName, null, null);
    }
}

myContentProvider.java (컨텐트프로바이더 내의 쿼리 처리)

package com.app.first; import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; import java.util.HashMap; public class myContentProvider extends ContentProvider { private SQLiteDatabase mDatabase; static final String PROVIDER_NAME = "com.app.first.myContentProvider"; private static HashMap<String, String> STUDENTS_PROJECTION_MAP; static final int GET_ALL = 1; static final int INSERT = 2; static final int UPDATE = 3; static final int DELETE = 4; static final UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "getAll", GET_ALL); uriMatcher.addURI(PROVIDER_NAME, "insert", INSERT); } @Override public boolean onCreate() { DBHelper dbHelper = new DBHelper(getContext()); mDatabase = dbHelper.getWritableDatabase(); return (mDatabase == null)? false:true; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { Log.d("test","uri : "+uri); SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables("my_table"); //switch (uriMatcher.match(uri)) { // case STUDENTS: // qb.setProjectionMap(STUDENTS_PROJECTION_MAP); // break; // case STUDENT_ID: // qb.appendWhere( _ID + "=" + uri.getPathSegments().get(1)); // break; // default: // } qb.setProjectionMap(STUDENTS_PROJECTION_MAP); if (sortOrder == null || sortOrder == ""){ sortOrder = /*NAME*/"contents"; } Cursor c = qb.query(mDatabase, projection, selection, selectionArgs,null, null, sortOrder); c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Nullable @Override public String getType(@NonNull Uri uri) { return null; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { return null; } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { return 0; } }


2. B앱 Mainfests (퍼미션 설정을 추가합니다.)

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

    <!-- 퍼미션 설정 -->
    <uses-permission android:name="com.app.first.READ_DATABASE" />
    <uses-permission android:name="com.app.first.WRITE_DATABASE" />
    <!-- 퍼미션 설정 -->

    <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">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.app.second.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
MainActivity.java (A앱의 myContentProvider에 쿼리를 날려 데이터를 가져옵니다.)
package com.app.second;

import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    String authority = "com.app.first.myContentProvider";

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

        Cursor c = getContentResolver().query(Uri.parse("content://"+authority+"/getdataall"), null, null, null, null);
        if(c == null)
            return;
        Log.e("test","aaabbb "+c.getCount());

        StringBuilder aa = new StringBuilder();
        while(c.moveToNext()) {
            String str = c.getLong(0) + " , " + c.getString(1)+" , "+c.getString(2)+" , "+c.getInt(3);
            System.out.println(str);
            aa.append(str+"\n");
        }
        c.close();

        TextView text = (TextView) findViewById(R.id.text);
        text.setText(aa);
    }
}



3. 결과 화면 


A앱                                                         B앱

    

+ Recent posts