32

사람들이 친구 그룹을 만들 수 있도록 앱을 설정하고 있습니다. 그룹이 생성되면 SQL 데이터베이스에 2 개의 테이블을 씁니다. 첫 번째 테이블에는 그룹 이름과 그룹 ID가 있습니다. 두 번째 테이블에는 두 개의 열, 그룹 ID 및 사용자 ID가 있습니다. 이것은 잘 작동합니다.커서 로더를 사용하여 Android에서 SQLite DB를 읽는 방법은 무엇입니까?

그러나 이제 데이터베이스에서 읽을 수 있기를 원합니다. cursorloader과 함께 listview 조각을 사용하고 있지만 정보를 표시하는 데 문제가 있습니다. 내 목록보기에서 첫 번째 테이블의 모든 그룹 이름을 나열하고 싶습니다.

내 문제는 내가 처음 onCreateLoader 방법에 content provider에서, 나는 Uri을 사용하고 내 연락처를 나열 cursorloader를 사용하는 경우, 점이다. 특히 나는 ContactsContracts.Contacts 클래스에서 CONTENT_URI을 가졌습니다. cursorloadercontentprovider와의

예 :

@Override 
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { 
    Uri contentUri = ContactsContract.Contacts.CONTENT_URI; 
    return new CursorLoader(getActivity(),contentUri,PROJECTION,SELECTION,ARGS,ORDER); 
} 

그러나, 콘텐츠 제공 업체를 사용하지 않고, 내가 return new CursorLoader(...)가 두 번째 인수에 Uri을 필요로하기 때문에 onCreateLoader 방법에 넣어 해야할지 모르겠어.

내 데이터베이스 데이터를 어떻게 목록보기에 표시 할 수 있을지에 대한 제안 사항이 있으십니까?

조각 클래스 코드 :

public class GroupListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> { 

CursorAdapter mAdapter; 
private OnItemSelectedListener listener; 
private static final String[] PROJECTION ={GroupContract.GroupDetails.COLUMN_NAME_GROUP_NAME}; 
private static final String SELECTION = null; 
final String[] FROM = {GroupContract.GroupDetails.COLUMN_NAME_GROUP_NAME}; 
final int[] TO = {android.R.id.text1}; 
private static final String[] ARGS = null; 
private static final String ORDER = null; 
private Cursor c; 


@Override 
public void onCreate(Bundle savedInstanceState){ 
    super.onCreate(savedInstanceState); 
    mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_1,null,FROM,TO,0); 
    ReadDBAsync readDB = new ReadDBAsync(); 
    readDB.execute(); 
} 

@Override 
public void onActivityCreated(Bundle savedInstanceState){ 
    super.onActivityCreated(savedInstanceState); 
    setListAdapter(mAdapter); 
    getLoaderManager().initLoader(0,null,this); 
} 

@Override 
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { 
    Uri contenturi = Uri.parse("content://preamble.oneapp"); 
    Uri tableuri = Uri.withAppendedPath(contenturi,GroupContract.GroupDetails.TABLE_NAME); 
    return new CursorLoader(getActivity(),tableuri,PROJECTION,SELECTION,ARGS,ORDER); 
} 

@Override 
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { 
    mAdapter.swapCursor(cursor); 
} 

@Override 
public void onLoaderReset(Loader<Cursor> cursorLoader) { 
    mAdapter.swapCursor(null); 
} 


private class ReadDBAsync extends AsyncTask<Void,Void,String> { 

    @Override 
    protected String doInBackground(Void... voids) { 

     ContractDBHelpers mDBHelper = new ContractDBHelpers(getActivity()); 
     SQLiteDatabase db = mDBHelper.getReadableDatabase(); 
     String returnvalue = "database read"; 
     c = db.query(GroupContract.GroupDetails.TABLE_NAME,PROJECTION,null,null,null,null,null); 
     return returnvalue; 
    } 

    @Override 
    protected void onPostExecute(String result){ 
     Toast.makeText(getActivity(), result, Toast.LENGTH_LONG).show(); 
    } 
} 

} 
+0

데이터베이스를 관리하기 위해 컨텐츠 공급자를 만들었습니까? – user936414

+0

@ user936414 아니요, 필요한가요? 그렇게 할 때의 이점/단점은 무엇입니까? 편집 : 그냥 그것을 읽고, 나는 여러 응용 프로그램에 걸쳐 데이터를 공유 할 필요가 없으므로 콘텐츠 공급자가 필요하지 않습니다. –

답변

35

이러한 목록 조각

1)에서 cursorloader를 작성하는 단계 SQLiteOpenHelper를 확장하는 클래스를 만들고 onCreateonUpgrade이 테이블을 만들 오버라이드 (override)합니다.

2) ContentProvider 확장 클래스를 만들고 URI를 만들어 데이터베이스에 액세스하십시오. http://developer.android.com/guide/topics/providers/content-providers.html을 참조하십시오. URI를 일치시키기 위해 onCreate, onUpdate, 쿼리 등 (오버라이드 된 메소드)에서 사용하는 URIMatcher에 URI를 추가하십시오. 참조 http://developer.android.com/reference/android/content/UriMatcher.html

3) 삽입 방법은 getContext().getContentResolver().notifyChange(uri, null)입니다. 쿼리 메서드에서 setNotificationUri(ContentResolver cr, Uri uri)을 호출 한 다음 삽입 변경 내용이 자동으로 로더에 반영되도록 콘텐츠 공급자를 반환하십시오. (https://stackoverflow.com/a/7915117/936414).

4) onCreateLoader에 해당 URI를 지정하십시오.

참고 : 콘텐츠 공급자가 없으면 목록의 변경 사항을 자동으로 새로 고치는 것이 현재 Android 버전에서 가능하지 않습니다. contentprovider를 표시하지 않으려면 manifest의 exported 속성을 false로 설정하십시오. 또는 https://stackoverflow.com/a/7422343/936414 에서처럼 사용자 정의 CursorLoader를 구현하여 데이터베이스에서 데이터를 검색 할 수 있습니다. 그러나이 경우 자동으로 데이터를 새로 고침 할 수 없습니다.

+9

정보를 주셔서 감사합니다. 나는 나의 옵션이'ContentProvider' (그렇지 않으면 내가 필요로하지 않는다)를 사용하거나 내 자신의 커스텀'CursorLoader' (추가 작업 인 것 같다)를 만드는 것이 이상하다는 것을 알았다. '컨텐츠 제공자'는 이미 추가 작업을하지 않고도 이것을 할 수있는 충분한 방법 일 것입니다. –

+0

콘텐츠 공급자가있는 이유 중 하나는 데이터베이스의 내용이 변경 될 때 (CursorLoader에 등록 된) 등록 된 모든 관찰자에게 알릴 수 있다는 것입니다. – user936414

+5

변경되지 않는 데이터 유형의 경우는 어떨까요? 나는 또한 ContentProvider를 사용해야한다는 것이 매우 이상하다는 것을 알았다. 정적 sqlite 데이터에 대한 더 빠르고 가벼운 솔루션이 있습니까? –

62

Android 가이드는 데이터를 다른 애플리케이션과 공유하고자 할 때 ContentProvider을 만들 것을 권장합니다. 이 필요가 없으면 클래스의 loadInBackgroud() 메서드를 재정의 할 수 있습니다. 예를 들어 다음과 같이 작성하십시오 onCreateLoader :

return new CursorLoader(YourContext, null, YourProjection, YourSelection, YourSelectionArgs, YourOrder) 
      { 
       @Override 
       public Cursor loadInBackground() 
       { 
        // You better know how to get your database. 
        SQLiteDatabase DB = getReadableDatabase(); 
        // You can use any query that returns a cursor. 
        return DB.query(YourTableName, getProjection(), getSelection(), getSelectionArgs(), null, null, getSortOrder(), null); 
       } 
      }; 
+12

내 데이터를 공유 할 필요가 없으며 내 데이터베이스 API를 ContentProvider로 리팩터링하지 않으므로이 방법을 사용합니다. 단점은 ContentProvider 항목이 없으면 내 listview는 ContentProviders에 대한 좋은 점 중 하나 인 데이터가 변경된시기를 자동으로 알지 못한다는 것입니다. 이제는'Cursor.requery() '대신'getLoaderManager(). restartLoader (MY_LOADER_ID, null, this); '를 사용하여 변경된 사항을 알고있을 때 로더를 다시 만들 수 있습니다. 이것은 어색하지만,'startManagingCursor()'접근법을 대체하는 가장 간단한 방법입니다. – Fish

+0

@Fish,이 정보를 제공해 주셔서 감사합니다. 그러나 지금 알고 계신 것은 ** 비싼'restartLoader()'가 될 수 있습니다 .. ** 중요합니다. – eRaisedToX

+0

YourProjection, YourSelection, YourSelectionArgs 및 YourOrder를 지정하지 않아도되는 이유가 있으면 AsyncTaskLoader를 반환하지 않아야합니다. – steamer25