ITKeyword,专注技术干货聚合推荐

注册 | 登录

解决android - Populating ListView with data from SQLite using CursorLoader

itPublisher 分享于

2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1062

2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址https://www.aliyun.com/minisite/goods

推荐:深入源码解析Android中Loader、AsyncTaskLoader、CursorLoader、LoaderManager

如果对Loader、AsyncTaskLoader、CursorLoader、LoaderManager等概念不明白或不知道如何使用Loader机制,可参见博文Android中Loader及LoaderManager的使用(附源

I made the simple test app based on this example. There is one button which inserts data to database and ListView. Both are in MainActivity. In original code was restartLoader() called only from onResume() but it refreshed the ListView only when the onResume() was executed. I put restartLoader() at the end of displayListView() and now it shows new row in the Listview after i push button. But i don't think that it is correct solution.

 public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor>{


      private SimpleCursorAdapter dataAdapter;

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

       displayListView();

       Button add = (Button) findViewById(R.id.add);
          add.setOnClickListener(new View.OnClickListener() {

               public void onClick(View v) {

                   ContentValues values = new ContentValues();
                   values.put(SensorsDb.KEY_TYPE, "wld");
                   values.put(SensorsDb.KEY_TITLE, "Basement Water Detector");
                   values.put(SensorsDb.KEY_SERIAL, "33");
                   values.put(SensorsDb.KEY_VALUE, "NO WATER");

                    getContentResolver().insert(MyContentProvider.CONTENT_URI,values);

                    displayListView();   
               }
              });
      }
      @Override
      protected void onResume() {
       super.onResume();
       //Starts a new or restarts an existing Loader in this manager
       getSupportLoaderManager().restartLoader(0, null, MainActivity.this);
      }

      private void displayListView() {
       // The desired columns to be bound
       String[] columns = new String[] {
        SensorsDb.KEY_TITLE,
        SensorsDb.KEY_VALUE
       };
       // the XML defined views which the data will be bound to
       int[] to = new int[] {
         R.id.sensorTitle,
         R.id.sensorState
       };

       // create an adapter from the SimpleCursorAdapter
       dataAdapter = new SimpleCursorAdapter(this, R.layout.custom_row_view, null, columns, to, 0);
       //Ensures a loader is initialized and active.
       getSupportLoaderManager().initLoader(0, null,  this);
       // get reference to the ListView
       ListView listView = (ListView) findViewById(R.id.sensorList);
       // Assign adapter to ListView
       listView.setAdapter(dataAdapter);

       getSupportLoaderManager().restartLoader(0, null, MainActivity.this);   
      }

      // This is called when a new Loader needs to be created.
      @Override
      public Loader<Cursor> onCreateLoader(int id, Bundle args) {
       String[] projection = {
         SensorsDb.KEY_ROWID,
         SensorsDb.KEY_TYPE,
         SensorsDb.KEY_TITLE,
         SensorsDb.KEY_SERIAL,
         SensorsDb.KEY_VALUE};
       CursorLoader cursorLoader = new CursorLoader(this,
         MyContentProvider.CONTENT_URI, projection, null, null, null);
       return cursorLoader;
      }

      @Override
      public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

             dataAdapter.swapCursor(data);
      }

      @Override
      public void onLoaderReset(Loader<Cursor> loader) {

       dataAdapter.swapCursor(null);
      }

      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
       getMenuInflater().inflate(R.menu.main, menu);
       return true;
      }
     }

There is MyContentProvider class

public class MyContentProvider extends ContentProvider{

 private MyDatabaseHelper dbHelper;

 private static final int ALL_SENSORS = 1;
 private static final int SINGLE_SENSOR = 2;

 // authority is the symbolic name of your provider
 // To avoid conflicts with other providers, you should use
 // Internet domain ownership (in reverse) as the basis of your provider authority.
 private static final String AUTHORITY = "com.example.contproctest.contentprovider";

 // create content URIs from the authority by appending path to database table
 public static final Uri CONTENT_URI =
  Uri.parse("content://" + AUTHORITY + "/sensors");

 // a content URI pattern matches content URIs using wildcard characters:
 // *: Matches a string of any valid characters of any length.
    // #: Matches a string of numeric characters of any length.
 private static final UriMatcher uriMatcher;
 static {
  uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  uriMatcher.addURI(AUTHORITY, "sensors", ALL_SENSORS);
  uriMatcher.addURI(AUTHORITY, "sensors/#", SINGLE_SENSOR);
 }

 // system calls onCreate() when it starts up the provider.
 @Override
 public boolean onCreate() {
  // get access to the database helper
  dbHelper = new MyDatabaseHelper(getContext());
  return false;
 }

 //Return the MIME type corresponding to a content URI
 @Override
 public String getType(Uri uri) {

  switch (uriMatcher.match(uri)) {
  case ALL_SENSORS:
   return "vnd.android.cursor.dir/vnd.com.example.contproctest.contentprovider.sensors";
  case SINGLE_SENSOR:
   return "vnd.android.cursor.item/vnd.com.example.contproctest.contentprovider.sensors";
  default:
   throw new IllegalArgumentException("Unsupported URI: " + uri);
  }
 }

 // The insert() method adds a new row to the appropriate table, using the values
 // in the ContentValues argument. If a column name is not in the ContentValues argument,
 // you may want to provide a default value for it either in your provider code or in
 // your database schema.
 @Override
 public Uri insert(Uri uri, ContentValues values) {

  SQLiteDatabase db = dbHelper.getWritableDatabase();
  switch (uriMatcher.match(uri)) {
  case ALL_SENSORS:
   //do nothing
   break;
  default:
   throw new IllegalArgumentException("Unsupported URI: " + uri);
  }
  long id = db.insert(SensorsDb.SQLITE_TABLE, null, values);
  getContext().getContentResolver().notifyChange(uri, null);
  return Uri.parse(CONTENT_URI + "/" + id);
 }

 // The query() method must return a Cursor object, or if it fails,
 // throw an Exception. If you are using an SQLite database as your data storage,
 // you can simply return the Cursor returned by one of the query() methods of the
 // SQLiteDatabase class. If the query does not match any rows, you should return a
 // Cursor instance whose getCount() method returns 0. You should return null only
 // if an internal error occurred during the query process.
 @Override
 public Cursor query(Uri uri, String[] projection, String selection,
   String[] selectionArgs, String sortOrder) {

  SQLiteDatabase db = dbHelper.getWritableDatabase();
  SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
  queryBuilder.setTables(SensorsDb.SQLITE_TABLE);

  switch (uriMatcher.match(uri)) {
  case ALL_SENSORS:
   //do nothing
   break;
  case SINGLE_SENSOR:
   String id = uri.getPathSegments().get(1);
   queryBuilder.appendWhere(SensorsDb.KEY_ROWID + "=" + id);
   break;
  default:
   throw new IllegalArgumentException("Unsupported URI: " + uri);
  }

  Cursor cursor = queryBuilder.query(db, projection, selection,
    selectionArgs, null, null, sortOrder);
  return cursor;

 }

 // The delete() method deletes rows based on the seletion or if an id is
 // provided then it deleted a single row. The methods returns the numbers
 // of records delete from the database. If you choose not to delete the data
 // physically then just update a flag here.
 @Override
 public int delete(Uri uri, String selection, String[] selectionArgs) {

  SQLiteDatabase db = dbHelper.getWritableDatabase();
  switch (uriMatcher.match(uri)) {
  case ALL_SENSORS:
   //do nothing
   break;
  case SINGLE_SENSOR:
   String id = uri.getPathSegments().get(1);
   selection = SensorsDb.KEY_ROWID + "=" + id
   + (!TextUtils.isEmpty(selection) ?
     " AND (" + selection + ')' : "");
   break;
  default:
   throw new IllegalArgumentException("Unsupported URI: " + uri);
  }
  int deleteCount = db.delete(SensorsDb.SQLITE_TABLE, selection, selectionArgs);
  getContext().getContentResolver().notifyChange(uri, null);
  return deleteCount;
 }

 // The update method() is same as delete() which updates multiple rows
 // based on the selection or a single row if the row id is provided. The
 // update method returns the number of updated rows.
 @Override
 public int update(Uri uri, ContentValues values, String selection,
   String[] selectionArgs) {
  SQLiteDatabase db = dbHelper.getWritableDatabase();
  switch (uriMatcher.match(uri)) {
  case ALL_SENSORS:
   //do nothing
   break;
  case SINGLE_SENSOR:
   String id = uri.getPathSegments().get(1);
   selection = SensorsDb.KEY_ROWID + "=" + id
   + (!TextUtils.isEmpty(selection) ?
     " AND (" + selection + ')' : "");
   break;
  default:
   throw new IllegalArgumentException("Unsupported URI: " + uri);
  }
  int updateCount = db.update(SensorsDb.SQLITE_TABLE, values, selection, selectionArgs);
  getContext().getContentResolver().notifyChange(uri, null);
  return updateCount;
 }

}
android sqlite listview android-loadermanager android-cursorloader
|
  this question
edited Sep 22 '13 at 20:25 asked Sep 22 '13 at 20:12 Radek Spinka 18 2 6

 | 

1 Answers
1

解决方法

You don't have to call restartLoader after insert new data in the CP because CursorLoader can listen your data and update itself automatically when there are changes in the data source (ContentProvider). Try to call cursor.setNotificationUri() before return the Cursor from the query method in your CP.

推荐:android实例 listview与sqlite数据绑定

ListView与Sqlite数据库绑定步骤: 1.将Sqlite数据库的内容查询出来并放入数组列表中,形成ListView的数据源; 2.适配器绑定数据源,显示在ListView item中。 本

@Override
public Cursor query(Uri uri, String[] projection, String selection,
 String[] selectionArgs, String sortOrder) {

  SQLiteDatabase db = dbHelper.getWritableDatabase();
  SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
  queryBuilder.setTables(SensorsDb.SQLITE_TABLE);

  switch (uriMatcher.match(uri)) {
  case ALL_SENSORS:
   //do nothing
   break;
  case SINGLE_SENSOR:
   String id = uri.getPathSegments().get(1);
   queryBuilder.appendWhere(SensorsDb.KEY_ROWID + "=" + id);
   break;
  default:
   throw new IllegalArgumentException("Unsupported URI: " + uri);
  }

  Cursor cursor = queryBuilder.query(db, projection, selection,
    selectionArgs, null, null, sortOrder);

  cursor.setNotificationUri(getContext().getContentResolver(), uri);

  return cursor;
}

|
  this answer
answered Sep 22 '13 at 21:12 rciovati 17.6k 2 62 97      can you give me solution of mine answer stackoverflow.com/questions/20419278/… –  user2567369 Dec 6 '13 at 9:27

 | 

推荐:Android简单的SQLite操作及ListView展示数据

学习Android有几天了,今天研究了下SQLite的简单操作,现在分享给奋斗在一线的苦逼程序员们,共勉吧。   Android系统提供了一个SQLiteOpenHelper的一个辅助类,


相关阅读排行


相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。