32

Ich richte meine App so ein, dass Leute Gruppen ihrer Freunde erstellen können. Wenn eine Gruppe erstellt wird, schreibt sie 2 Tabellen in die SQL-Datenbank. Die erste Tabelle hat einen Gruppennamen und eine Gruppen-ID. Die zweite Tabelle hat 2 Spalten, eine Gruppen-ID und eine Benutzer-ID. Das funktioniert gut.Wie liest man eine SQLite DB in Android mit einem Cursorloader?

Jetzt möchte ich jedoch aus der Datenbank lesen können. Ich verwende ein Listview-Fragment mit einer cursorloader, aber ich habe Probleme, die Informationen anzuzeigen. Ich möchte alle Gruppennamen aus der ersten Tabelle in meiner Listenansicht auflisten.

Mein Problem ist, dass, wenn ich zum ersten Mal der cursorloader verwenden meine Kontakte zur Liste, ich war ein Uri vom content provider im onCreateLoader Verfahren. Konkret hatte ich CONTENT_URI aus der ContactsContracts.Contacts Klasse.

Beispiel cursorloader mit contentprovider:

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

jedoch ohne einen Content-Provider mit, ich weiß nicht, was in der onCreateLoader Methode zu setzen, weil return new CursorLoader(...) ein Uri im zweiten Argumente erfordert.

Irgendwelche Vorschläge, wie ich meine Datenbankdaten in einer Listview anzeigen könnte?

Fragment Klassencode:

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

Haben Sie einen Inhaltsanbieter erstellt, um Ihre Datenbank zu verwalten? – user936414

+0

@ user936414 nein, ist das notwendig? Was sind die Vorteile/Nachteile dabei? Edit: nur lesen Sie es auf, ich brauche nicht die Daten über mehrere Anwendungen zu teilen, so dass ich keinen Content-Provider –

Antwort

35

Dies sind die Schritte, um eine cursorloader in einer Liste Fragment

1) Erstellen Sie eine Klasse SQLiteOpenHelper zu erstellen und zu überschreiben onCreate und onUpgrade Erweiterung Ihrer Tabellen zu erstellen.

2) Erstellen Sie eine Klasse, die ContentProvider erweitert, und erstellen Sie die URIs für den Zugriff auf Ihre Datenbank. Siehe http://developer.android.com/guide/topics/providers/content-providers.html. Fügen Sie Ihre URIs zur URIMatcher, die Sie in onCreate, onUpdate, Abfrage usw. verwenden (überschriebene Methoden), um den URI zu finden. Siehe http://developer.android.com/reference/android/content/UriMatcher.html

3) In der Einfügemethode rufen Sie getContext().getContentResolver().notifyChange(uri, null). Rufen Sie in der Abfrage-Methode setNotificationUri(ContentResolver cr, Uri uri) vor dem Zurückgeben des Inhaltsanbieters für die Einfügungsänderung automatisch an Ihren Loader. (https://stackoverflow.com/a/7915117/936414).

4) Geben Sie diesen URI in onCreateLoader.

Hinweis: Ohne einen Inhaltsanbieter ist die automatische Aktualisierung der Änderungen an der Liste nicht möglich, wie von der aktuellen Android-Version. Wenn Sie Ihren Inhaltsanbieter nicht sichtbar machen möchten, setzen Sie das exportierte Attribut im Manifest auf false. Oder Sie können Ihren benutzerdefinierten CursorLoader wie in https://stackoverflow.com/a/7422343/936414 implementieren, um Daten aus der Datenbank abzurufen. Aber in diesem Fall ist eine automatische Aktualisierung der Daten nicht möglich

+9

danke für Ihre Informationen brauche Ich werde es untersuchen. Ich finde es merkwürdig, dass meine Optionen darin bestehen, einen 'ContentProvider' zu verwenden (was ich sonst nicht brauche) oder meinen eigenen'CursorLoader' zu erstellen (was zusätzliche Arbeit zu sein scheint) ... würde die Datenbank nicht abfragen ohne eine "content provider" ist so weit verbreitet, dass sie dies bereits ohne zusätzliche Arbeit getan hätten? –

+0

Einer der Gründe für contentprovider ist, dass sie alle registrierten (in CursorLoader registrierten) Beobachter benachrichtigen können, wenn sich der Inhalt in der Datenbank ändert. – user936414

+5

was ist, wenn dies eine Art von Daten, die sich nicht ändert? Ich finde es auch sehr seltsam, gezwungen zu sein, einen 'ContentProvider' zu verwenden. Gibt es keine schnellere/leichtere Lösung für statische SQL-Daten? –

62

Android Guide schlägt vor, eine ContentProvider zu erstellen, wenn Sie Ihre Daten mit anderen Anwendungen teilen möchten. Wenn Sie dies nicht benötigen, können Sie einfach die Methode loadInBackgroud() der Klasse CursorLoader überschreiben. Zum Beispiel schreiben Sie so in Ihrem 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

Dies ist, was ich benutze, weil ich meine Daten nicht teilen muss, und ich möchte meine Datenbank API nicht zu einem ContentProvider umgestalten. Der Nachteil ist, dass ohne die Inhalte von ContentProvider meine Listenansichten nicht automatisch wissen, wann sich die Daten geändert haben, was eines der netten Dinge an ContentProvidern ist. Um das zu umgehen, erstelle ich meine Loader neu, wenn ich weiß, dass eine Änderung vorgenommen wurde, d. H. Anstatt "Cursor.requery()" aufzurufen, verwende ich jetzt "getLoaderManager(). RestartLoader (MY_LOADER_ID, null, this);'. Das ist peinlich, aber es ist der einfachste Weg, den ich gefunden habe, den 'startManagingCursor()' Ansatz zu ersetzen. – Fish

+0

@Fish, Danke für diese Info, aber was ich jetzt wissen möchte ist ** wie teuer 'restartLoader()' sein kann ..? ** Das ist richtig? – eRaisedToX

+0

Warum sollte ich keinen AsyncTaskLoader zurückgeben, wenn ich YourProjection, YourSelection, YourSelectionArgs und YourOrder nicht angeben möchte? – steamer25

Verwandte Themen