Hello Android学习之SQLite(二)

 

上节说到当我们遇到成百上千的语句时查找数据库内容该怎么办,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 + ')'
                  : "");
   }
}

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








 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值