Hello Android学习之SQLite(二)

来源:互联网 发布:求积分的软件 编辑:程序博客网 时间:2024/05/12 21:23

 

上节说到当我们遇到成百上千的语句时查找数据库内容该怎么办,Android提供了一个更加好的办法,那就是Data Binding,它允许我们从数据库到试图仅仅少量的代码。为了演示Data Binding我们来修改上次的代码。

1.       首先来修改Event.java,让其继承ListActivity类代替Activity类。

2.       我们需要修改showEvent方法,代码如下:

private static int[] TO ={R.id.rowid,R.id.time,R.id.title};    private void showEvents(Cursor cursor){    //Set up data binding    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,    R.layout.item, cursor, FROM, TO);    setListAdapter(adapter);    }

你会发现代码比以前少了很多,我们为Cursor方法创建了SimpleCursorAdapter,然后告诉ListActivity来用这个新的adapter,这个adapter把View和数据库连接了一来。SimpleCursorAdapter中有五个参数:

context:是指现在所用的Activity。

Layout:试图(View)所在的资源,也就是路径。

Cursor:数据库连接用的cursor。

From:列表每个的名字,也就是数据是从哪里来的

To:这些数据是到那里的试图

3.       新增一个列表定义在layout/item.xml中,你会发现这里的row ID,time,title将会被TO引用。代码如下:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="horizontal"    android:padding="10sp">    <TextView         android:id="@+id/rowid"        android:layout_width="wrap_content"        android:layout_height="wrap_content"/>    <TextView        android:id="@+id/rowidcolon"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text=":"        android:layout_toRightOf="@id/rowid"/>    <TextView         android:id="@+id/time"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_toRightOf="@id/rowidcolon"/>    <TextView         android:id="@+id/timecolon"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text=":"        android:layout_toRightOf="@id/time"/>    <TextView         android:id="@+id/title"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:ellipsize="end"        android:singleLine="true"        android:textStyle="italic"        android:layout_toRightOf="@id/timecolon"/></RelativeLayout>

4.       修改layout/main.xml中的代码:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"><ListView     android:id="@android:id/list"    android:layout_width="wrap_content"    android:layout_height="wrap_content"/><TextView     android:id="@android:id/empty"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="@string/empty"/></LinearLayout>

由于这个activity是继承ListActivity的,android寻找两个特别的layout文件,如果列表中已经存在文件,则会调用android:id/list来展示view,否则会调用android:id/empty来显示No events.

5.       添加strings.xml文件中的内容如下:

<string name="app_name">Events</string><string name="empty">No events!</string>

这时你就会看见不一样的效果了,新的问题又出现了,当用户选择一条数据,当他选择想看其中的内容的时候或者想要删除这条数据,将要怎么办呢?但是没有什么应用程序是来进行这样的操作的,所以我们需要用到ContentProvider。

在Android安全模型中,一个应用程序编写的文件无法被其他任何应用程序所读写。每个程序都有自己的Linux用户ID和数据目录(data/data/包名),以及其受保护的内存空间。Android程序可通过下面两种方式进行彼此间的通信。
a. IPC(Inter-Process Communication,进程间通信):一个进程使用AIDL(接口定义语言)和Ibinder接口声明一个任意的API。调用该API时,将在进程间安全且有效地对参数进行编组,这项先进技术用于对后台Service线程进行远程过程调用。
b. ContentProvider:进程中系统中将它们本身注册为某些数据类型的提供者。请求信息时,Android就会通过一个固定的API调用这些进程,以它们认为合适的方式查询或修改内容。
任何信息在被ContentProvider处理时,都会通过URI格式为 content://authority/path/id 。

其中的参数为:
content://是标准要求的前缀;
authority:是提供者的名称,建议你使用完全限定包名称,避免出现名称冲突;
path:是提供者内部的一个虚拟目录,用于标识被请求的数据类型;
id:是被请求的特定记录的主键,要请求获得具有特定类型的所有记录,可以省略此参数以及后面的斜杠。

6.所以我们需要多增加两个常量到Constants.java中。

7.  改变主程序中onCreate()代码如下:

package com.zy.events;import static com.zy.events.Constants.TIME;import static com.zy.events.Constants.TITLE;import static android.provider.BaseColumns._ID;import static com.zy.events.Constants.CONTENT_URI;import android.app.ListActivity;import android.content.ContentValues;import android.database.Cursor;import android.os.Bundle;import android.widget.SimpleCursorAdapter;public class Events extends ListActivity {        @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);addEvent("Hell,Android!");Cursor cursor = getEvents();showEvents(cursor);    }        private void addEvent(String string){    //Insert a new record into the Events data source.    //You would do something similar for delete and update.    ContentValues values = new ContentValues();    values.put(TIME, System.currentTimeMillis());    values.put(TITLE, string);    getContentResolver().insert(CONTENT_URI, values);    }        private static String[] FROM ={_ID,TIME,TITLE};    private static String ORDER_BY = TIME + " DESC";    private Cursor getEvents(){    //Perform a managed query. The Activity will handle cloding    //and re-querying the cursor when needed.    return managedQuery(CONTENT_URI, FROM, null, null, ORDER_BY);    }        private static int[] TO ={R.id.rowid,R.id.time,R.id.title};    private void showEvents(Cursor cursor){    //Set up data binding    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,    R.layout.item, cursor, FROM, TO);    setListAdapter(adapter);    }}

8.  新增EventsProvider继承于ContentProvider:

ContentProvider是一个类似于Activity的高级对象,需要向系统进行声明。因此,实现ContentProvider的第一步是将其添加到AndroidManifest.xml文件中的<activity>标签之前(作为<application>的子标签)。
<provider android:name=”EventsProvider”
android:authorities=”com.zy.events” />
android:name是类名,android:authorities是在内容URI中使用的字符串。
EventsProvider.java代码如下:

package com.zy.events;import static android.provider.BaseColumns._ID;import static com.zy.events.Constants.AUTHORITY;import static com.zy.events.Constants.CONTENT_URI;import static com.zy.events.Constants.TABLE_NAME;import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.net.Uri;import android.text.TextUtils;public class EventsProvider extends ContentProvider {   private static final int EVENTS = 1;   private static final int EVENTS_ID = 2;   /** The MIME type of a directory of events */   private static final String CONTENT_TYPE      = "vnd.android.cursor.dir/vnd.example.event";   /** The MIME type of a single event */   private static final String CONTENT_ITEM_TYPE      = "vnd.android.cursor.item/vnd.example.event";   private EventsData events;   private UriMatcher uriMatcher;   // ...   @Override   public boolean onCreate() {      uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);      uriMatcher.addURI(AUTHORITY, "events", EVENTS);      uriMatcher.addURI(AUTHORITY, "events/#", EVENTS_ID);      events = new EventsData(getContext());      return true;   }   @Override   public Cursor query(Uri uri, String[] projection,         String selection, String[] selectionArgs, String orderBy) {      if (uriMatcher.match(uri) == EVENTS_ID) {         long id = Long.parseLong(uri.getPathSegments().get(1));         selection = appendRowId(selection, id);      }      // Get the database and run the query      SQLiteDatabase db = events.getReadableDatabase();      Cursor cursor = db.query(TABLE_NAME, projection, selection,            selectionArgs, null, null, orderBy);      // Tell the cursor what uri to watch, so it knows when its      // source data changes      cursor.setNotificationUri(getContext().getContentResolver(),            uri);      return cursor;   }   @Override   public String getType(Uri uri) {      switch (uriMatcher.match(uri)) {      case EVENTS:         return CONTENT_TYPE;      case EVENTS_ID:         return CONTENT_ITEM_TYPE;      default:         throw new IllegalArgumentException("Unknown URI " + uri);      }   }   @Override   public Uri insert(Uri uri, ContentValues values) {      SQLiteDatabase db = events.getWritableDatabase();      // Validate the requested uri      if (uriMatcher.match(uri) != EVENTS) {         throw new IllegalArgumentException("Unknown URI " + uri);      }      // Insert into database      long id = db.insertOrThrow(TABLE_NAME, null, values);      // Notify any watchers of the change      Uri newUri = ContentUris.withAppendedId(CONTENT_URI, id);      getContext().getContentResolver().notifyChange(newUri, null);      return newUri;   }      @Override   public int delete(Uri uri, String selection,         String[] selectionArgs) {      SQLiteDatabase db = events.getWritableDatabase();      int count;      switch (uriMatcher.match(uri)) {      case EVENTS:         count = db.delete(TABLE_NAME, selection, selectionArgs);         break;      case EVENTS_ID:         long id = Long.parseLong(uri.getPathSegments().get(1));         count = db.delete(TABLE_NAME, appendRowId(selection, id),               selectionArgs);         break;      default:         throw new IllegalArgumentException("Unknown URI " + uri);      }      // Notify any watchers of the change      getContext().getContentResolver().notifyChange(uri, null);      return count;   }      @Override   public int update(Uri uri, ContentValues values,         String selection, String[] selectionArgs) {      SQLiteDatabase db = events.getWritableDatabase();      int count;      switch (uriMatcher.match(uri)) {      case EVENTS:         count = db.update(TABLE_NAME, values, selection,               selectionArgs);         break;      case EVENTS_ID:         long id = Long.parseLong(uri.getPathSegments().get(1));         count = db.update(TABLE_NAME, values, appendRowId(               selection, id), selectionArgs);         break;      default:         throw new IllegalArgumentException("Unknown URI " + uri);      }      // Notify any watchers of the change      getContext().getContentResolver().notifyChange(uri, null);      return count;   }      /** Append an id test to a SQL selection expression */   private String appendRowId(String selection, long id) {      return _ID + "=" + id            + (!TextUtils.isEmpty(selection)                  ? " AND (" + selection + ')'                  : "");   }}

这个显示效果如上图,现在我们已经有了事件存储的框架了,这样就可以被其他的应用程序所用,甚至被其他的程序员来进行开发。