• Android 用SQLite 使用 CursorLoader 中的数据填充列表视图


    我做了简单的测试应用程序基于此示例。有一个按钮,插入到数据库和列表视图的数据。都是在 MainActivity 中。在原来的代码是restartLoader() 仅从调用 onResume() ,但它刷新列表视图时才 onResume() 被执行死刑。我把 restartLoader() 在结束了displayListView() 和现在它显示新行在列表视图中后我按下按钮。但我不认为它是正确的解决方案。

     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;
          }
         }
    有 MyContentProvider 类
    
    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;
     }
    
    }
    解决方法 1:
    你不需要调用 restartLoader 后在 CP 中插入新的数据,因为 CursorLoader 可以听您的数据和 (ContentProvider) 的数据源中发生更改时自动更新。尝试在调用 cursor.setNotificationUri() 之前返回 Cursor 从你 CP 的查询方法。
    
    @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;
    }
  • 相关阅读:
    源码分析清楚 AbstractQueuedSynchronizer
    Java 并发队列 BlockingQueue
    ReentrantLock以及AQS实现原理
    Java并发之Condition
    Java线程的6种状态及切换
    同步工具类
    Java 并发实践 — ConcurrentHashMap 与 CAS
    Java7/8 中的 HashMap 和 ConcurrentHashMap
    java HashMap、HashTable、ConcurrentHashMap区别
    Mysql的复制原理以及流程
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/6594980.html
Copyright © 2020-2023  润新知