android之数据库和Content Provider(三)

使用Content Provider

介绍Content Resolver

ContentResolver cr = getContentResolver();

使用ContentResolver 对Content Provider进行事务操作。

直接看例子:

// Get the Content Resolver. 
ContentResolver cr = getContentResolver();

// Specify the result column projection. Return the minimum set 
// of columns required to satisfy your requirements. 
String[] result_columns = new String[] { 
     MyHoardContentProvider.KEY_ID, 
     MyHoardContentProvider.KEY_GOLD_HOARD_ACCESSIBLE_COLUMN, 
     MyHoardContentProvider.KEY_GOLD_HOARDED_COLUMN };

// Specify the where clause that will limit your results. 
String where = MyHoardContentProvider.KEY_GOLD_HOARD_ACCESSIBLE_COLUMN 
                  + “=” + 1;

// Replace these with valid SQL statements as necessary. 
String whereArgs[] = null; 
String order = null;

// Return the specified rows. 
Cursor resultCursor = cr.query(MyHoardContentProvider.CONTENT_URI, 
  result_columns, where, whereArgs, order);

很多Content Provider也包含一个快捷URI模式,允许你去操作一个指定行的数据,通过对URI附加ID。 你可以使用ContentUris的静态方法withAppendedId.

// Get the Content Resolver. 
ContentResolver cr = getContentResolver();

// Specify the result column projection. Return the minimum set 
// of columns required to satisfy your requirements. 
String[] result_columns = new String[] { 
        MyHoardContentProvider.KEY_ID, 
        MyHoardContentProvider.KEY_GOLD_HOARD_NAME_COLUMN, 
        MyHoardContentProvider.KEY_GOLD_HOARDED_COLUMN };

// Append a row ID to the URI to address a specific row. 
Uri rowAddress = 
  ContentUris.withAppendedId(MyHoardContentProvider.CONTENT_URI, 
  rowId);

// These are null as we are requesting a single row. 
String where = null; 
String whereArgs[] = null; 
String order = null;

// Return the specified rows. 
Cursor resultCursor = cr.query(rowAddress, 
  result_columns, where, whereArgs, order);

 

根据返回的结果集存在Cursor中,对Cursor操作:

float largestHoard = 0f; 
String hoardName = “No Hoards”;

// Find the index to the column(s) being used. 
int GOLD_HOARDED_COLUMN_INDEX = resultCursor.getColumnIndexOrThrow(  
    MyHoardContentProvider.KEY_GOLD_HOARDED_COLUMN); 
int HOARD_NAME_COLUMN_INDEX = resultCursor.getColumnIndexOrThrow(  
    MyHoardContentProvider.KEY_GOLD_HOARD_NAME_COLUMN);

// Iterate over the cursors rows. 
// The Cursor is initialized at before first, so we can 
// check only if there is a “next” row available. If the 
// result Cursor is empty, this will return false. 
while (resultCursor.moveToNext()) {  
     float hoard = resultCursor.getFloat(GOLD_HOARDED_COLUMN_INDEX);  
     if (hoard > largestHoard) {  
          largestHoard = hoard;  
          hoardName = resultCursor.getString(HOARD_NAME_COLUMN_INDEX);  
        }  
  }

// Close the Cursor when you’ve finished with it. 
resultCursor.close();

 

操作完记得关Cursor.避免内存泄露。

为了保证APP的流畅度,这些对数据库的操作最好是异步的。

使用Cursor Loader实现异步操作

数据库的操作是耗时的,所以避免在主线程操作数据库是必要的。

自己去管理Cursor,在UI进程异步准确操作是困难的。 为了简化这些步骤,Android 3.0(API level 11) 引入Loader类。Loader也同样在Android Support Library可用。

介绍Loaders

LoaderManager来管理Loader,在每个Activity和Fragment内可访问。这些都是被设计用来异步加载数据和监视底层数据源的变化。

Cursor Loader观察数据源的变化,所以你不再需要去实现你自己的内容观察者。LoaderManager管理Cursor的生命周期,确保当Activity被结束后,它也关闭。

 

实现CursorLoader回调函数

为了使用CursorLoader,你需要去创建并实现一个新的LoaderManager.LoaderCallbacks.

LoaderManager.LoaderCallbacks<Cursor> loaderCallback
     = new LoaderManager.LoaderCallbacks<Cursor>() {

这种匿名实现的方式是在你觉得你只是需要一个简单的Loader实现。

 

介绍Loader的回调函数:

1.onCreateLoader 当loader 被初始化的时候触发这个函数,在这个函数中,你需要创建和返回一个新的Cursor Loader对象。Cursor Loader构建参数需要使用ContentResolver执行一个查询。

2.onLoadFinished 当LoaderManager已经完成异步查询,这个函数会被调用,结果集Cursor会作为参数传递进来。你就可以使用这个Cursor去更新你的adapter和其他UI元素。

3.onLoadReset 当LoaderManager重置你的CursorLoader,这个函数会被调用。在这个函数中,你应该释放所有对查询所得数据的引用和重置UI。Cursor会被LoaderManager关闭,所以你不应该尝试去关闭它。

注意:onLoadFinished和onLoadReset不是异步的。

下面展示onCreatLoader的框架代码:

public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
   // Construct the new query in the form of a Cursor Loader. Use the id 
   // parameter to construct and return different loaders. 
   String[] projection = null;


  String where = null; 
  String[] whereArgs = null; 
  String sortOrder = null;

  // Query URI 
  Uri queryUri = MyContentProvider.CONTENT_URI;

  // Create the new Cursor loader. 
  return new CursorLoader(DatabaseSkeletonActivity.this, queryUri, 
     projection, where, whereArgs, sortOrder); 
}

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 
  // Replace the result Cursor displayed by the Cursor Adapter with 
  // the new result set. 
  adapter.swapCursor(cursor);

  // This handler is not synchronized with the UI thread, so you 
  // will need to synchronize it before modifying any UI elements 
  // directly. 
}

public void onLoaderReset(Loader<Cursor> loader) { 
  // Remove the existing result Cursor from the List Adapter. 
  adapter.swapCursor(null);

  // This handler is not synchronized with the UI thread, so you 
  // will need to synchronize it before modifying any UI elements 
  // directly. 
}

 

 

初始化和重启CursorLoader

LoaderManager loaderManager = getLoaderManager();

想要初始化你一个新的CursorLoader,只需调用Loader Manager的initLoader方法,传递一个Loader回调实现的引用,还有一个可选择的参数Bundle和一个loader标示符。
Bundle args = null;
loaderManager.initLoader(LOADER_ID, args, myLoaderCallbacks);

这些步骤通常在主Activity的onCreate方法内完成。(又或者是Fragment的onActivityCreated函数)。

如果标示符所指定的loader不存在,那么会被创建在相关的Loader回调函数onCreateLoader中,就像前面所提到的。

在更多的情况,这是最需要做的。LoaderManager管着Loaders的生命周期和底层查询,Cursors。类似的,它还会管理结果集的改变。

Loader已经被创建后,若你重复调用initLoader会简单得返回已经存在的loader。如果你想放弃先前创建的Loader,想重新创建它,你可以使用restartLoader方法。
loaderManager.restartLoader(LOADER_ID, args, myLoaderCallbacks);

这个典型发生在,当你的查询参数发生变化的时候。

 

增加,删除和更新Content

在Content Provider上执行事务,Content Resolver使用insert,delete和update方法. 就像查询,除非将这些操作移到另外个工作线程,不然就会执行在主线程。

1.insert

Content Resolver提供2个插入记录的方法:

1.insert 单记录插入

涉及一个Content Values对象

2.bulkInsert 批量插入

涉及一个Content Values数组

例子:

// Create a new row of values to insert. 
ContentValues newValues = new ContentValues();

// Assign values for each row. 
newValues.put(MyHoardContentProvider.KEY_GOLD_HOARD_NAME_COLUMN,  
            hoardName); 
newValues.put(MyHoardContentProvider.KEY_GOLD_HOARDED_COLUMN,  
            hoardValue); 
newValues.put(MyHoardContentProvider.KEY_GOLD_HOARD_ACCESSIBLE_COLUMN,  
            hoardAccessible); 
// [ ... Repeat for each column / value pair ... ]

// Get the Content Resolver 
ContentResolver cr = getContentResolver();

// Insert the row into your table 
Uri myRowUri = cr.insert(MyHoardContentProvider.CONTENT_URI, 
                                         newValues);

 

2. delete

直接例子:

// Specify a where clause that determines which row(s) to delete. 
// Specify where arguments as necessary. 
String where = MyHoardContentProvider.KEY_GOLD_HOARDED_COLUMN + 
                   “=” + 0; 
String whereArgs[] = null;

// Get the Content Resolver. 
ContentResolver cr = getContentResolver();

// Delete the matching rows 
int deletedRowCount = 
   cr.delete(MyHoardContentProvider.CONTENT_URI, where, whereArgs);


3.update

直接例子:
// Create the updated row content, assigning values for each row.  
ContentValues updatedValues = new ContentValues(); 
updatedValues.put(MyHoardContentProvider.KEY_GOLD_HOARDED_COLUMN, 
                             newHoardValue); 
// [ ... Repeat for each column to update ... ]

// Create a URI addressing a specific row. 
Uri rowURI =  
      ContentUris.withAppendedId(MyHoardContentProvider.CONTENT_URI, 
          hoardId);

// Specify a specific row so no selection clause is required. 
String where = null; 
String whereArgs[] = null;            

// Get the Content Resolver. 
ContentResolver cr = getContentResolver();

// Update the specified row. 
int updatedRowCount = 
  cr.update(rowURI, updatedValues, where, whereArgs);

 

 

访问存储在Content Provider中的文件

访问或者插入一个新的文件,简单的分别实用ContentResolver的openOutputStream或者openInputStream。将Content Provider 中你所需要的某条包含文件的记录 URI传递进去。

public void addNewHoardWithImage(String hoardName, float hoardValue, 
           boolean hoardAccessible, Bitmap bitmap) {

           // Create a new row of values to insert. 
           ContentValues newValues = new ContentValues();

           // Assign values for each row. 
           newValues.put(MyHoardContentProvider.KEY_GOLD_HOARD_NAME_COLUMN, 
                            hoardName); 
           newValues.put(MyHoardContentProvider.KEY_GOLD_HOARDED_COLUMN, 
                            hoardValue); 
           newValues.put( 
             MyHoardContentProvider.KEY_GOLD_HOARD_ACCESSIBLE_COLUMN, 
             hoardAccessible);

           // Get the Content Resolver 
           ContentResolver cr = getContentResolver();

           // Insert the row into your table 
           Uri myRowUri = 
             cr.insert(MyHoardContentProvider.CONTENT_URI, newValues);

           try { 
             // Open an output stream using the new row’s URI. 
             OutputStream outStream = cr.openOutputStream(myRowUri); 
             // Compress your bitmap and save it into your provider.


     bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outStream); 
   } 
   catch (FileNotFoundException e) { 
     Log.d(TAG, “No file found for this record.”); 
   } 
}

public Bitmap getHoardImage(long rowId) { 
   Uri myRowUri = 
     ContentUris.withAppendedId(MyHoardContentProvider.CONTENT_URI, 
                                      rowId);

   try { 
     // Open an input stream using the new row’s URI. 
     InputStream inStream = 
        getContentResolver().openInputStream(myRowUri);

     // Make a copy of the Bitmap. 
     Bitmap bitmap = BitmapFactory.decodeStream(inStream); 
     return bitmap; 
   } 
     catch (FileNotFoundException e) { 
     Log.d(TAG, “No file found for this record.”); 
   }

   return null; 
}

 

你可能感兴趣的:(android,Provider,content,loader)