This article used the knowledge there are a few: SQLiteOpenHelper, Cursor, CursorAdapter, ContentProvider, ContentObserver
SQLiteOpenHelper is typically used to manipulate a database, and when you create an instance of this class, you get an SQLiteDatabase, which is actually used to manipulate the database.
Let’s take a look at an example of SQLiteOpenHelper
package com.bvin.study.observer;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper{
public DBHelper(Context context){
super(context,"cache",null,Config.DATA_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table person(_id integer primary key autoincrement,name string,sex string,age integer)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
Copy the code
This class is responsible for database creation and version update management. In general, it is possible to add, delete, and modify an instance of this class, SQLiteDatabase. SQLiteDatabase already encapsulates various operations on the database, and it also provides a db.execSQL(SQL, bindArgs) method to execute native SQL statements, which some say is more efficient than what it encapsulates. ExecSQL (), however, does not return a value. Let’s take a look at what those methods return.
SQLiteDatabase
1.public long insert (String table, String nullColumnHack, ContentValues values)
Values returns the ID of the row that was inserted into the table.
2.public int update (String table, ContentValues values, String whereClause, String[] whereArgs)
This method is followed by what conditions to update the records that meet the conditions, return the updated record row.
3.public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, StringorderBy, String limit)
Returns the query result set
4.public int delete (String table, String whereClause, String[] whereArgs)
Returns which row was deleted
An asynchronous query AsyncQueryHandler can be used for a query, but this class can also add or delete the query, override each method separately to make a response
(2) the ContentProvider
This is one of the four components of Android, so you don’t need to manually instantiate it, just register the ContentProvider in androidmanifest.xml.
<provider android:/>
Copy the code
Android :name specifies the class name, and Android :authorities specifies the unique identifier, which must be the same as the URI.
ContentProvider uri forms like domain: the content: / / authorities / / path, it is very important to this uri.
Path can represent a table followed by a field in a row, such as/person/18/name, which represents the name of the 18th person in the Person table
The UI is called the Uniform Resource Locator, which uniquely identifies the resource so that other applications can use your data. The Android system itself provides a large number of providers such as SMS, contacts, etc
Okay, so with urIs out of the way, it’s the ContentProvider’s turn.
ContentProvider is not normally constructed actively, but provides an entry method like an Activity. Light ContentProvider can not ah, the so-called clever housewife can not cook a meal without rice. So where is the meter? The meter is using the DBHelper that we made. DBHelper gets the database SQLiteDatabase, which is the real database. The ContentProvider covers the various methods used to manipulate the database, and SQLiteDatabase is used to perform each operation.
Take a look at the internal implementation of ContentProvider
package com.bvin.study.observer; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; public class MyProvide extends ContentProvider{ DBHelper dbHelper; @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub long rowId = -1; rowId =dbHelper.getWritableDatabase().insert(Config.TABLE_NAME, null, values); Uri cururi = Uri.withAppendedPath(Config.CONTENT_URI, rowId+""); this.getContext().getContentResolver().notifyChange(uri,null); return cururi; } @Override public boolean onCreate() { // TODO Auto-generated method stub dbHelper = new DBHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO Auto-generated method stub return null; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; }}Copy the code
I’m just using the insert method here, but how is it called externally? Use a class called ContentResolver, which can be retrieved from the Context. ContentResolver also has insert(),update(),query().delete() methods, But the ContentResolver method is the exposed method that really implements the ContetnProvider. ContentResolver is like a car, it can advance, retreat, turn and brake, and The ContetnProvider is the driver. The car you see outside turns and brakes are all operated by the driver, but does the driver have these functions? No driver can turn and brake on behalf of the car. These core functions are the steering wheel and brake functions of the car, so SQLiteDatabase is the steering wheel.
(3) the ContentResolver
The previous ones are providing the functional interface service. Now we’ll see how to invoke it. Here we use a ListActivity to call the above defined services and data visualization, the main interface is a Listview, the operation of the database with menus to function, four menus are respectively add delete check change.
@Override public Boolean onCreateOptionsMenu(Menu Menu) {// TODO auto-generated method stub menu.add(0, 0, 0, "add "); Menu. add(0, 1, 1, "query "); Menu. add(0, 2, 2, "change "); Menu. add(0, 3, 3, "delete "); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // TODO Auto-generated method stub switch(item.getItemId()){ case 0: ContentValues cv = new ContentValues(); CV. Put ("name", "chu Ling "); getContentResolver().insert(Config.CONTENT_URI, cv); break; case 1: break; case 2: dbHelper.getWritableDatabase().execSQL("update "+Config.TABLE_NAME+" set name = 'chuling' where _id = 2"); adapter.notifyDataSetChanged(); break; case 3: dbHelper.getWritableDatabase().delete(Config.TABLE_NAME, null, null); break; } return super.onOptionsItemSelected(item); }Copy the code
If you follow the above code, the insert operation listView will not come out in time, and you can see the new item after restarting the program. Insert a cursor into the ListView to display a cursor, that is, update the data in time to refresh the UI interface, because the ListView is bound to a CursorAdapter and this cursor is used to query the database, so there are two things to do. One is the data source to update and then is to notify the UI data adapter has changed, cursor will query again and again or adapter to replace cursor, and then calling adapter. The notifyDataSetChanged (); But cursor. Requery () will affect the efficiency, and the light on the adapter. The notifyDataSetChanged () interface is not updated, originally wanted to use ContentObserver, finally feel doesn’t fit, Is there a good way to update Listview in a timely manner?
DBHelper dbHelper = null;
SimpleCursorAdapter adapter;
Cursor cursor;
Handler handler;
MyObserver observer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
dbHelper = new DBHelper(this);
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.what==2013){
if(cursor!=null&&!cursor.isClosed()&&adapter!=null){
adapter.notifyDataSetChanged();
}
}
}
};
cursor = dbHelper.getReadableDatabase().rawQuery("select * from "+Config.TABLE_NAME, null);
adapter = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,cursor, new String[]{"name"}, new int[]{android.R.id.text1});
setListAdapter(adapter);
observer = new MyObserver(this,handler,cursor);
getContentResolver().registerContentObserver(Config.CONTENT_URI, false, observer);
}
Copy the code
Config.CONTENT_URI: the string that holds the kite is a ContentResolver. I’m not looking at cursor.requery(), but I already have this in ContentObserver. It also has a handler that registers ContentObserver and handles messages sent by observers.
(4) ContentObserver
The constructor of this class must have a Handler argument to communicate with, and it must override the onChanged() method to send a message to the Activity using Handler.
package com.bvin.study.observer; import android.content.AsyncQueryHandler; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; import android.os.Message; public class MyObserver extends ContentObserver{ private Handler handler; private Cursor cursor; private Context context; public MyObserver(Context context,Handler handler,Cursor cursor){ super(handler); this.context = context; this.handler = handler; this.cursor = cursor; } @Override public void onChange(boolean selfChange) { // TODO Auto-generated method stub super.onChange(selfChange); cursor.requery(); handler.sendEmptyMessage(2013); }}Copy the code
The purpose of the cursor is to use the onChanged() method to query the cursor when the database that the registered URI points to is updated, and then use the Adapter to notify the Activity Handler that the interface is updated. It is not practical to update the Listview with this method. The handler can handle other UI elements, such as data insertion, and pop up a dialog box saying “data insertion completed”.
Below I still send all the code, it seems that you can not send attachments.
Main interface: mainactivity.java
package com.bvin.study.observer; import android.app.ListActivity; import android.content.AsyncQueryHandler; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.view.Menu; import android.view.MenuItem; import android.widget.SimpleCursorAdapter; public class MainActivity extends ListActivity { /** Called when the activity is first created. */ DBHelper dbHelper = null; SimpleCursorAdapter adapter; Cursor cursor; Handler handler; MyObserver observer; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.main); dbHelper = new DBHelper(this); handler = new Handler(){ @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); if(msg.what==2013){ if(cursor! =null&&! cursor.isClosed()&&adapter! =null){ adapter.notifyDataSetChanged(); }}}}; cursor = dbHelper.getReadableDatabase().rawQuery("select * from "+Config.TABLE_NAME, null); adapter = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_1,cursor, new String[]{"name"}, new int[]{android.R.id.text1}); setListAdapter(adapter); observer = new MyObserver(this,handler,cursor); getContentResolver().registerContentObserver(Config.CONTENT_URI, false, observer); } @override public Boolean onCreateOptionsMenu(Menu Menu) {// TODO auto-generated method stub menu.add(0, 0, 0, "add "); Menu. add(0, 1, 1, "query "); Menu. add(0, 2, 2, "change "); Menu. add(0, 3, 3, "delete "); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // TODO Auto-generated method stub switch(item.getItemId()){ case 0: ContentValues cv = new ContentValues(); CV. Put ("name", "chu Ling "); getContentResolver().insert(Config.CONTENT_URI, cv); break; case 1: break; case 2: dbHelper.getWritableDatabase().execSQL("update "+Config.TABLE_NAME+" set name = 'chuling' where _id = 2"); adapter.notifyDataSetChanged(); break; case 3: dbHelper.getWritableDatabase().delete(Config.TABLE_NAME, null, null); break; } return super.onOptionsItemSelected(item); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); if(dbHelper! =null){ dbHelper.close(); } getContentResolver().unregisterContentObserver(observer); }}Copy the code
MyProvider.java
package com.bvin.study.observer; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; public class MyProvide extends ContentProvider{ DBHelper dbHelper; @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; } @Override public Uri insert(Uri uri, ContentValues values) { // TODO Auto-generated method stub long rowId = -1; rowId =dbHelper.getWritableDatabase().insert(Config.TABLE_NAME, null, values); Uri cururi = Uri.withAppendedPath(Config.CONTENT_URI, rowId+""); this.getContext().getContentResolver().notifyChange(uri,null); return cururi; } @Override public boolean onCreate() { // TODO Auto-generated method stub dbHelper = new DBHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO Auto-generated method stub return null; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated method stub return 0; }}Copy the code
DBHelper.java
package com.bvin.study.observer;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper{
public DBHelper(Context context){
super(context,"cache",null,Config.DATA_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table person(_id integer primary key autoincrement,name string,sex string,age integer)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
Copy the code
MyObserver.java
package com.bvin.study.observer; import android.content.AsyncQueryHandler; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; import android.os.Message; public class MyObserver extends ContentObserver{ private Handler handler; private Cursor cursor; private Context context; public MyObserver(Context context,Handler handler,Cursor cursor){ super(handler); this.context = context; this.handler = handler; this.cursor = cursor; } @Override public void onChange(boolean selfChange) { // TODO Auto-generated method stub super.onChange(selfChange); cursor.requery(); handler.sendEmptyMessage(2013); }}Copy the code
Config.java
package com.bvin.study.observer;
import android.net.Uri;
public class Config {
public static final String AOTHORITY = "com.bvin.study.observer.MyProvide";
public static final String TABLE_NAME = "person";
public static final Uri CONTENT_URI = Uri.parse("content://"+AOTHORITY+"/"+TABLE_NAME);
public static final int DATA_VERSION =1;
}
Copy the code
AndroidManifest.xml
<? The XML version = "1.0" encoding = "utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.bvin.study.observer" android:versionCode="1" android:version > <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android: android:label="@string/app_name" > <intent-filter> <action android: /> <category android: /> </intent-filter> </activity> <provider android:/> </application> </manifest>Copy the code