Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 720|回复: 0

2.高焕堂讲解 ContentProvider范例 - [高焕堂讲义]

[复制链接]

该用户从未签到

发表于 2011-9-28 14:06:05 | 显示全部楼层 |阅读模式
1.  何谓Android的嫡系组件

    Android有4项一等公民(或称为嫡系亲属),包括:Activity、ContentProvider、IntentReceiver与Service。它们都必须宣告于AndroidManifest.xml档案里,如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.misoo.SQ03">
    <uses-permission xmlns:android="http://schemas.android.com/apk/res/android"  
         android:name="android.permission.INTERNET">
    </uses-permission>
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <provider android:name="DataProvider"
            android:authorities="com.misoo.provider.SQ03">
        </provider>
        <activity android:name=".ac01" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".DispActivity" android:label="DispActivity">
        </activity>
    </application>
</manifest>

    这让Android知道我们城市里定义了多少个嫡系组件类别;Android可以在启动时就将它们执行起来,成为共享的(Shared)服务组件。这些嫡系服务组件间的沟通,通常是透过「意图」(Intent)对象来请Android转达给对方,Android则会依据意图而找出最佳的配对。配对成功,就展开相互的沟通与服务了。

2.   什么是ContentProvider嫡系组件
---- 以SQLite为例

    在Android里,SQLite数据库是最典型的ContentProvider,负责储存各式各样的内容。除了数据库之外,还有许多其它种类的ContentProvider。在这里并不是要介绍这些ContentProvider,而是要透过SQLite认识ContentProvider接口,然后将舶来Linter组件,配上这种ContentProvider接口,让它摇身一变成为Android的嫡系组件。


2.1  一般(即非嫡系)SQLite的范例

      没有透过ContentProvider接口来使用SQLite,就是对SQLite的「非嫡系」用法。此时,应用程序透过JDBC接口和SQL语句来与SQLite沟通,以存取数据库里的内容。先认识这种传统用法。此范例将从SQLite读取数据。首先建立一个程序项目,其含有两个java程序文件:ac01.java和DataProvider.java。其中,ac01.java 是典型的Activity类别,负责UI画面的显示工作,而DataProvider则负责与SQLite沟通。其详细程序代码为:

/* ----- ac01.java 程序代码 ------*/
package com.misoo.pklx;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class ac01 extends ListActivity {
    private static final String[] PROJECTION = new String[] { "stud_no", "stud_name" };

    @Override protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
        DataProvider dp = new DataProvider(this);
        Cursor cur = dp.query(PROJECTION, null, null, null);
        ArrayList<Map<String, Object>> coll
                = new ArrayList<Map<String, Object>>();
        Map<String, Object> item;
        cur.moveToFirst();
        while(!cur.isAfterLast()) {
          item = new HashMap<String, Object>();
          item.put("c1", cur.getString(0) + ",  " + cur.getString(1));
          coll.add(item);
          cur.moveToNext();
        }
        dp.close();
        this.setListAdapter(new SimpleAdapter(this, coll,
              android.R.layout.simple_list_item_1, new String[] { "c1" },
              new int[] {android.R.id.text1}));
    }
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
          finish();
}}

    指令:
           DataProvider dp = new DataProvider(this);

     这和一般类别之用法是一样的。ac01对象指名要诞生一个DataProvider的物件。然后呼叫它,如下指令:
          Cursor cur = dp.query(PROJECTION, null, null, null);

这要求SQLite从数据库查询出某些数据。详细的DataProvider.java程序代码如下:

/* ----- DataProvider.java 程序代码 ------*/
package com.misoo.pklx;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class DataProvider {
    private static final String DATABASE_NAME = "StudDB";
    private static final String TABLE_NAME = "Student";
    private final int DB_MODE = Context.MODE_PRIVATE;
    private SQLiteDatabase db=null;
     
    public DataProvider(Context ctx) {
       try {  db = ctx.openOrCreateDatabase(DATABASE_NAME, DB_MODE, null);   }
catch (Exception e) {  Log.e("ERROR", e.toString());   return;   }

       try { db.execSQL("drop table "+ TABLE_NAME); }
catch (Exception e) {  Log.e("ERROR", e.toString());   }

       db.execSQL("CREATE TABLE " + TABLE_NAME + " ("  + "stud_no" + " TEXT,"
                        + "stud_name" + " TEXT" + ");");
      String sql_1 = "insert into "+ TABLE_NAME +
" (stud_no, stud_name) values('S101', 'Lily');";
String sql_2 = "insert into " + TABLE_NAME +
" (stud_no, stud_name) values('S102', 'Linda');";
      String sql_3 = "insert into " + TABLE_NAME +
" (stud_no, stud_name) values('S103', 'Bruce');";

   try {  db.execSQL(sql_1);   db.execSQL(sql_2);  db.execSQL(sql_3); }
catch (SQLException e) {  Log.e("ERROR", e.toString());  return;  }
   }
    public Cursor query(String[] projection, String selection, String[] selectionArgs,
                      String sortOrder) {
          Cursor cur = db.query(TABLE_NAME, projection, null, null, null, null, null);
           return cur;
    }
    public void close(){   db.close();   }
}

这种用法属于非嫡系的用法:在ac01.java程序代码里,其指令:
           DataProvider dp = new DataProvider(this);

明确指定由DataProvider对象来提供服务。反之,嫡系用法则是透过意图(Intent)来请Android代为配对,进而找出适当的ContentProvider对象来为aco1对象提供服务。


2.2  嫡系SQLite的范例

    刚才的范例里,我们直接使用DataProvider类别的接口来与SQLite沟通。本节的范例,将替DataProvider配上ContentProvider接口,让ac01对象能透过ContentProvider新接口来沟通。此范例也是从SQLite数据库读取3笔数据;请仔细看看其程序代码的微妙差异:

/* ----- ac01.java 程序代码 ------*/
package com.misoo.pkrr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class ac01 extends ListActivity {
    public static int g_variable;
    public static final String AUTHORITY = "com.misoo.provider.rx09-02";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
            + "/Student");
    private static final String[] PROJECTION
              = new String[]{ "stud_no", "stud_name"};
    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        if (intent.getData() == null)  intent.setData(CONTENT_URI);
        Cursor cur = getContentResolver().query(getIntent().getData(),
                PROJECTION, null, null, null);
        ArrayList<Map<String, Object>> coll = new ArrayList<Map<String, Object>>();
        Map<String, Object> item;
        cur.moveToFirst();
        while (!cur.isAfterLast()) {
            item = new HashMap<String, Object>();
            item.put("c1", cur.getString(0) + ",  " + cur.getString(1));
            coll.add(item);
            cur.moveToNext();
        }
        this.setListAdapter(new SimpleAdapter(this, coll,
                android.R.layout.simple_list_item_1, new String[] { "c1" },
                new int[] { android.R.id.text1 }));
    }
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) { finish();}
}

   指令:
              Cursor cur = getContentResolver().query(getIntent().getData(),
                       PROJECTION, null, null, null);

要求Android代为寻找适合的ContentProvider来提供服务,并不刻意指定由DataProvider对象来担任。只要合乎ConentProvider接口,且符合意图条件的对象皆可以来为ac01对象提供服务。于是,ac01程序代码就不再直接呼叫DataProvider类别的函数了,而是呼叫ContentProvider接口所提供的函数。再来仔细看看DataProvider类别与ContentProvider接口的搭配情形:

/* ----- DataProvider.java 程序代码 ------*/
package com.misoo.pkrr;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.util.Log;

public class DataProvider extends ContentProvider {
    private static final String DATABASE_NAME = "StudNewDB";
    private static final int DATABASE_VERSION = 2;
    private static final String TABLE_NAME = "StudTable";
    private static class DatabaseHelper extends SQLiteOpenHelper {
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);  }
        @Override    public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE " + TABLE_NAME + " (" + "stud_no"
                    + " TEXT," + "stud_name" + " TEXT" + ");");
            String sql_1 = "insert into " + TABLE_NAME
                    + " (stud_no, stud_name) values('S1001', &#39am');";
            String sql_2 = "insert into " + TABLE_NAME
                    + " (stud_no, stud_name) values('S1002', 'Steve');";
            String sql_3 = "insert into " + TABLE_NAME
                    + " (stud_no, stud_name) values('S1003', 'John');";
            try { db.execSQL(sql_1);  db.execSQL(sql_2);  db.execSQL(sql_3);    }
catch (SQLException e) { Log.e("ERROR", e.toString());    }
        }
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
    }
    // ---------------------------------------------------------------------------------
    private DatabaseHelper mOpenHelper;
    @Override    public boolean onCreate() {
        mOpenHelper = new DatabaseHelper(getContext());  return true;  }
    @Override    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        Cursor c = db.query(TABLE_NAME, projection, null, null, null, null,    null);
        return c;
    }
    @Override    public String getType(Uri uri) {    return null;  }
    @Override    public Uri insert(Uri uri, ContentValues initialValues) { return uri;    }
    @Override    public int delete(Uri uri, String where, String[] whereArgs) { return 0; }
    @Override    public int update(Uri uri, ContentValues values, String where,
            String[] whereArgs)
{  return 0;  }
}

     类别定义:
           public class DataProvider extends ContentProvider {
// …..…..
}

DataProvider类别继承ContentProvider父类别,也继承了它的接口定义。ContentProvider接口定义了多个函数,主要包括:
l           query()函数---- 它查询出合乎某条件的数据。
l           insert()函数---- 它将存入一笔新资料。
l           delete()函数---- 它删除合乎某条件的资料。
l           update()函数---- 更新某些笔数据的内容。

     在这个DataProvider类别里,撰写了query()函数内的指令,来实现query()接口,这个query()函数实际呼叫SQLite数据库的功能。也就是说,ac01等应用程序透过ContentProvider接口间接呼叫到DataProvider的query()函数,然后此query()函数才使用SQLite的服务。
     由于此范例的DataProvider已经是ContentProvider嫡系身份了,必须由Android来启动它,而不是有ac01等应用程序来直接启动它,所以必须在AndroidManifest.xml文档里给Android一些指示,如下:

/* ----- AndroidManifest.xml 文檔 ------*/
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.misoo.pkrr"
      android:versionCode="1"
      android:versionName="1.0.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ac01"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider android:name="DataProvider"
            android:authorities="com.misoo.provider.rx09-02">
        </provider>
    </application>
</manifest>

这特别说明DataProvider是一个ContentProvider,于是Android就会来启动它。
回复

使用道具 举报

该用户从未签到

发表于 2012-3-26 23:24:03 | 显示全部楼层
谢谢分享!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-11 23:54 , Processed in 0.297931 second(s), 36 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表