java攻城獅之路(Android篇)--ListView與ContentProvider

一.ListView
1.三種Adapter構建ListView
ListView添加條目的時候, 可使用setAdapter(ListAdapter)方法, 經常使用的ListAdapter有三種
BaseAdapter: 定義一個類繼承BaseAdapter, 重寫4個抽象方法, ListView的條目是由getView()方法構建出來的
SimpleAdapter: 建立SimpleAdapter對象時, 傳入數據(List<Map<String, ?>>), 並指定數據的綁定關係
SimpleCursorAdapter: 建立SimpleCursorAdapter對象時, 傳入一個Cursor, 指定數據的綁定關係css

練習一:html

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.shellway.sqlite.MainActivity" 
    android:background="@color/abc_search_url_text_normal">

    <ListView
        android:id="@+id/id_LV"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
         />

</RelativeLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" 
    android:padding="10dp"
    >
    
    <TextView 
        android:id="@+id/idTV"
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="1"
        />
    <TextView 
        android:id="@+id/nameTV"
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:gravity="center"
        android:text="張三"
        />
    <TextView 
        android:id="@+id/balanceTV"
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:gravity="center"
        android:text="10000"
        />

</LinearLayout>
item.xml
package com.shellway.sqlite;

import java.util.List;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {

    private ListView lv;
    private List<Person> persons;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.id_LV); //獲取ListView
        PersonDAO dao = new PersonDAO(this);
        persons = dao.findAll();
        //給ListView添加Adapter,按照Adapter中的方法對ListView添加條目
        lv.setAdapter(new myAdapter()); 
        
    }
    //定義Adapter,把每一個Person對象生成一個條目,將全部條目裝入ListView
    private class myAdapter extends BaseAdapter{

        @Override
        public int getCount() {  //返回ListView中要裝入的條目的數量
            return persons.size();
        }

        @Override
        public Object getItem(int position) {//點哪一個條目就返回哪一個條目的對象
            return persons.get(position);
        }

        @Override
        public long getItemId(int position) {//返回條目的ID
            return position;
        }

        @Override
        //返回指定位置上的View,會被添加到ListView中(即一個Person構建成一個View,而後掛到ListView)
        public View getView(int position, View convertView, ViewGroup parent) {
            Person p = persons.get(position);
            //構建成一個條目(View),第三個參數是要掛到誰身上,這裏寫null它會自動返回到LListView中
            View item = View.inflate(getApplicationContext(), R.layout.item, null);
            TextView idTV = (TextView) item.findViewById(R.id.idTV);
            TextView nameTV = (TextView) item.findViewById(R.id.nameTV);
            TextView balanceTV = (TextView) item.findViewById(R.id.balanceTV);
            idTV.setText(p.getId()+"");
            nameTV.setText(p.getName());
            balanceTV.setText(p.getBalance()+"");
            return item;
        }
    }
}
MainActivity

SimpleAdapter:java

注意:若要修改爲SimpleAdapter,不要忘記了修改AndroidManifest.xml中下面加粗位置部分。android

        <activity
            android:name=".SimpleAdapterActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
package com.shellway.sqlite;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

public class SimpleAdapterActivity extends ActionBarActivity {

    private ListView lv;
    private List<Person> persons;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.id_LV); //獲取ListView
        PersonDAO dao = new PersonDAO(this);
        persons = dao.findAll();
        List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();
        for (Person p : persons) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("id", p.getId());
            map.put("name", p.getName());
            map.put("balance", p.getBalance());
            data.add(map);
        }
        lv.setAdapter(new SimpleAdapter(this, data , R.layout.item, 
                new String[]{"id","name","balance"},
                new int[]{R.id.idTV,R.id.nameTV,R.id.balanceTV}));
        /**SimpleAdapter
         * 參數1:上下文環境
         * 參數2:數據,List<Map<String, Object>>每一個Person裝入一個Map,再將Map裝入List
         * 參數3:佈局文件的資源id
         * 參數4:Map中的Key,和參數5中的id對應,將指定key的value放入View中指定id對應和組件上
         * 參數5:View中的id
         */
    }
}
SimpleAdapter

SimpleCusorAdapter:git

注意:使用SimpleCusorAdapter,在查詢結果中要包含有「_id」這一列,這裏我把id取別名爲_id的方法解決。github

    public Cursor queryAllCusor(){
        SQLiteDatabase db = helper.getReadableDatabase();
        //Cursor c = db.rawQuery("select id,name,balance from people", null);
        Cursor c = db.query("people", new String[]{"id as _id","name","balance"}, null, null, null, null, null, null);
        return c;
    }
package com.shellway.sqlite;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.ActionBarActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

public class SimpleCusorAdapterActivity extends ActionBarActivity {

    private ListView lv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.id_LV); //獲取ListView
        PersonDAO dao = new PersonDAO(this);
        Cursor c = dao.queryAllCusor();
        lv.setAdapter(new SimpleCursorAdapter(this, R.layout.item, c, 
                new String[]{"_id","name","balance"}, 
                new int[]{R.id.idTV,R.id.nameTV,R.id.balanceTV}));
        /**SimpleAdapter
         * 參數1:上下文環境
         * 參數2:佈局文件的資源id
         * 參數3:包含數據的遊標
         * 參數4:遊標中的列名
         * 參數5:條目中的組件的ID,遊標中的數據就會放在對應的這些組件上
         */
    }
}
SimpleCusorAdapterActivity

運行結果:sql

2.監聽ListView的點擊
調用ListView.setOnItemClickListener(OnItemClickListener)方法註冊一個監聽器
在監聽器的onItemClick()方法中使用 parent.getItemAtPosition(position) 方法能夠獲取指定條目上的數據
BaseAdapter: 返回的就是自定義的getItem()方法中返回的數據
SimpleAdapter: 返回的是一個Map, 就是建立SimpleAdapter時List中的一個Map
SimpleCursorAdapter: 返回的是一個Cursor, 這個Cursor就是建立時傳入的Cursor, 可是已經經過moveToPosition()方法指定到點擊的索引了shell

練習2:數據庫

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.shellway.sqlite.SimpleAdapterActivity" 
    android:background="@color/abc_search_url_text_normal">
    
<LinearLayout 
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" 
    >
    
    <TextView 
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="序號"
        />
    <TextView 
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:gravity="center"
        android:text="姓名"
        />
    <TextView 
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:gravity="center"
        android:text="餘額"
        />
</LinearLayout>
    
    <ListView
        android:id="@+id/id_LV"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_below="@id/ll"
    />

</RelativeLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" 
    android:padding="10dp"
    >
    
    <TextView 
        android:id="@+id/idTV"
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="1"
        />
    <TextView 
        android:id="@+id/nameTV"
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:gravity="center"
        android:text="張三"
        />
    <TextView 
        android:id="@+id/balanceTV"
        android:textSize="20sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:gravity="center"
        android:text="10000"
        />

</LinearLayout>
item.xml
package com.shellway.sqlite;

import java.util.List;

import android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class BaseAdapterActivity extends ActionBarActivity {

    private ListView lv;
    private List<Person> persons;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.id_LV); //獲取ListView
        PersonDAO dao = new PersonDAO(this);
        persons = dao.findAll();
        //給ListView添加Adapter,按照Adapter中的方法對ListView添加條目
        lv.setAdapter(new myAdapter()); 
        //給ListView添加條目點擊監聽器
        lv.setOnItemClickListener(new myOnClickListener());
        
    }
    
    private class myOnClickListener implements OnItemClickListener{
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            //獲取點擊的條目上的數據,其內部其實是調用:myAdapter.getItem()
              Person p = (Person) parent.getItemAtPosition(position);
              Toast.makeText(getApplicationContext(), p.getBalance()+"", Toast.LENGTH_SHORT).show();
        }
    }
    
    //定義Adapter,把每一個Person對象生成一個條目,將全部條目裝入ListView
    private class myAdapter extends BaseAdapter{

        @Override
        public int getCount() {  //返回ListView中要裝入的條目的數量
            return persons.size();
        }

        @Override
        public Object getItem(int position) {//點哪一個條目就返回哪一個條目的對象
            return persons.get(position);
        }

        @Override
        public long getItemId(int position) {//返回條目的ID
            return position;
        }

        @Override
        //返回指定位置上的View,會被添加到ListView中(即一個Person構建成一個View,而後掛到ListView)
        public View getView(int position, View convertView, ViewGroup parent) {
            Person p = persons.get(position);
            //構建成一個條目(View),第三個參數是要掛到誰身上,這裏寫null它會自動返回到LListView中
            View item = View.inflate(getApplicationContext(), R.layout.item, null);
            TextView idTV = (TextView) item.findViewById(R.id.idTV);
            TextView nameTV = (TextView) item.findViewById(R.id.nameTV);
            TextView balanceTV = (TextView) item.findViewById(R.id.balanceTV);
            idTV.setText(p.getId()+"");
            nameTV.setText(p.getName());
            balanceTV.setText(p.getBalance()+"");
            return item;
        }
    }
}
BaseAdapterActivity添加ListView中條目點擊監聽事件
package com.shellway.sqlite;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class SimpleAdapterActivity extends ActionBarActivity {

    private ListView lv;
    private List<Person> persons;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.id_LV); //獲取ListView
        PersonDAO dao = new PersonDAO(this);
        persons = dao.findAll();
        List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();
        for (Person p : persons) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("id", p.getId());
            map.put("name", p.getName());
            map.put("balance", p.getBalance());
            data.add(map);
        }
        lv.setAdapter(new SimpleAdapter(this, data , R.layout.item, 
                new String[]{"id","name","balance"},
                new int[]{R.id.idTV,R.id.nameTV,R.id.balanceTV}));
        /**SimpleAdapter
         * 參數1:上下文環境
         * 參數2:數據,List<Map<String, Object>>每一個Person裝入一個Map,再將Map裝入List
         * 參數3:佈局文件的資源id
         * 參數4:Map中的Key,和參數5中的id對應,將指定key的value放入View中指定id對應和組件上
         * 參數5:View中的id
         */
        lv.setOnItemClickListener(new myOnClickListener());
    }
    private class myOnClickListener implements OnItemClickListener{
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            //SimpleAdapter返回的是一個map
              Map<String,Object> map =  (Map<String, Object>) parent.getItemAtPosition(position);
              Toast.makeText(getApplicationContext(), map.get("name").toString(), Toast.LENGTH_SHORT).show();
        }
    }
}
SimpleAdapterActivity添加ListView中條目點擊監聽事件
package com.shellway.sqlite;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.ActionBarActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class SimpleCusorAdapterActivity extends ActionBarActivity {

    private ListView lv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.id_LV); //獲取ListView
        PersonDAO dao = new PersonDAO(this);
        Cursor c = dao.queryAllCusor();
        lv.setAdapter(new SimpleCursorAdapter(this, R.layout.item, c, 
                new String[]{"_id","name","balance"}, 
                new int[]{R.id.idTV,R.id.nameTV,R.id.balanceTV}));
        /**SimpleAdapter
         * 參數1:上下文環境
         * 參數2:佈局文件的資源id
         * 參數3:包含數據的遊標
         * 參數4:遊標中的列名
         * 參數5:條目中的組件的ID,遊標中的數據就會放在對應的這些組件上
         */
        lv.setOnItemClickListener(new myOnClickListener());
    }
    
    private class myOnClickListener implements OnItemClickListener{
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            //SimpleCursorAdapter返回的是一個Cursor
              Cursor c = (Cursor) parent.getItemAtPosition(position);
              Toast.makeText(getApplicationContext(), c.getString(0), Toast.LENGTH_SHORT).show();
        }
    }
}
SimpleCusorAdapterActivity添加ListView中條目點擊監聽事件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.shellway.sqlite"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
        <instrumentation
        android:targetPackage="com.shellway.sqlite"
        android:name="android.test.InstrumentationTestRunner" />
    
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
     <uses-library android:name="android.test.runner" />
        <activity
            android:name=".BaseAdapterActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
AndroidManifest.xml

輔助類:app

package com.shellway.sqlite;

public class Person {
    
    private Integer id;
    private String name;
    private Integer balance;
    public Person() {
        super();
    }
    public Person(String name, Integer balance) {
        super();
        this.name = name;
        this.balance = balance;
    }
    public Person(Integer id, String name, Integer balance) {
        super();
        this.id = id;
        this.name = name;
        this.balance = balance;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getBalance() {
        return balance;
    }
    public void setBalance(Integer balance) {
        this.balance = balance;
    }
    @Override
    public String toString() {
        return "person [id=" + id + ", name=" + name + ", balance=" + balance
                + "]";
    }
}
Person.java
package com.shellway.sqlite;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBSQLiteHelper extends SQLiteOpenHelper {
    public DBSQLiteHelper(Context context){
        super(context,"data.db" , null, 4);
        /**
         * 因爲弗雷沒有無參的構造函數,必須顯式調用有參的構造函數
         * 參數1:上下文環境,用來肯定數據庫文件存儲的目錄
         * 參數2:數據庫文件的名字
         * 參數3:生成遊標的工廠,填null就是使用默認的
         * 參數4:數據庫的版本,從1開始
         */
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
      System.out.println("onCreate");
      db.execSQL("CREATE TABLE people(id INTEGER PRIMARY KEY AUTOINCREMENT,name VACHAR(20))");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
     System.out.println("onUpgrade");
     db.execSQL("ALTER TABLE people ADD balance INTEGER");
    }
}
DBSQLiteHelper.java
package com.shellway.sqlite;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class PersonDAO {
    private DBSQLiteHelper helper;
    
    public PersonDAO(Context context) {
        helper = new DBSQLiteHelper(context);
    }
    
    public long insert(Person p){
         SQLiteDatabase db = helper.getWritableDatabase();//獲取數據庫連接(可寫的)
        //db.execSQL("INSERT INTO people(name,balance) VALUES(?,?)", new Object[]{p.getName(),p.getBalance()} );
         ContentValues values = new ContentValues();
         values.put("name", p.getName());
         values.put("balance", p.getBalance());
         /**
          * 這裏的第二個參數 能夠隨便填表裏的任意一個字段名,是爲了防止插入的字段名爲空時會出錯,
          * 當你肯定插入的值不會出錯時候能夠null
          * 返回值表示最新插入的記錄的ID
          */
         long rows = db.insert("people", null, values);
         db.close();
         return rows;
    }
    public void delete(Integer id){
        SQLiteDatabase db = helper.getWritableDatabase();
        //db.execSQL("DELETE FROM people WHERE id = ?", new Object[]{id});
        db.delete("people", "id=?", new String[]{id+""});
        db.close();
    }
    public void update(Person p){
        SQLiteDatabase db = helper.getWritableDatabase();
        //db.execSQL("update people set name=?,balance=? where id=? ", new Object[]{p.getName(),p.getBalance(),p.getId()});
        ContentValues values = new ContentValues();
        values.put("name", p.getName());
        values.put("balance", p.getBalance());
        db.update("people", values, "id=?", new String[]{p.getId()+""});
        db.close();
    }
    //根據id查詢某條記錄
    public Person query(Integer id){
        /**
         * 查詢時候應該優先使用getReadableDatabase()而不是getWritableDatabase(),
         * 其實getReadableDatabase是先獲取getWritableDatabase,若獲取失敗則採用getReadableDatabase
         */
        SQLiteDatabase db = helper.getReadableDatabase();
        //Cursor c = db.rawQuery("select name,balance from people where id=?",new String[]{id+""});
        Cursor c = db.query("people", new String[]{"id","name","balance"}, "id=?", new String[]{id+""}, null, null, null, null);
        Person p = null ;
        if (c.moveToNext()) {
            String name = c.getString(c.getColumnIndex("name"));
            int balance = c.getInt(2);//若直接用下標方式,則注意該字段的索引,遊標的索引是從0開始的
            p = new Person(id,name,balance);
        }
        c.close();
        db.close();
        return p;
    }
    //查詢所有記錄
    public List<Person> findAll(){
        SQLiteDatabase db = helper.getReadableDatabase();
        //Cursor c = db.rawQuery("select id,name,balance from people", null);
        Cursor c = db.query("people", null, null, null, null, null, null, null);
        List<Person>  persons = new ArrayList<Person>();
        while (c.moveToNext()) {
            Person p = new Person(c.getInt(0),c.getString(1),c.getInt(2));
            persons.add(p);
        }
        c.close();
        db.close();
        return persons;
    }
    public Cursor queryAllCusor(){
        SQLiteDatabase db = helper.getReadableDatabase();
        //Cursor c = db.rawQuery("select id,name,balance from people", null);
        Cursor c = db.query("people", new String[]{"id as _id","name","balance"}, null, null, null, null, null, null);
        return c;
    }
    //查詢記錄總條數
    public int queryCount(){
        SQLiteDatabase db = helper.getReadableDatabase();
        //Cursor c = db.rawQuery("select count(*) from people", null);
        Cursor c = db.query("people", new String[]{"count(*)"}, null, null, null, null, null);
        c.moveToNext();
        int i = c.getInt(0);
        c.close();
        db.close();
        return i;
    }
    //分頁查詢
    public List<Person> queryPage(int pageNum,int capacity){
        String offset = (pageNum-1) * capacity +"";  //偏移量,便是第幾頁的頁數
        String len = capacity + "";                  //一頁中顯示的個數
        SQLiteDatabase db = helper.getReadableDatabase();
        //Cursor c = db.rawQuery("select id,name,balance from people limit ?,?", new String[]{offset,len});
        Cursor c = db.query("people", new String[]{"id","name","balance"}, null, null, null, null, null, offset+","+len);
        List<Person>  persons = new ArrayList<Person>();
        while (c.moveToNext()) {
            Person p = new Person(c.getInt(0),c.getString(1),c.getInt(2));
            persons.add(p);
        }
        c.close();
        db.close();
        return persons;
    }
}
PersonDAO.java
package com.shellway.sqlite;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.database.sqlite.SQLiteDatabase;
import android.provider.SyncStateContract.Helpers;
import android.test.AndroidTestCase;

public class TestSQLite extends AndroidTestCase {
     public void test1(){
         DBSQLiteHelper helper = new DBSQLiteHelper(getContext());
         SQLiteDatabase sql = helper.getWritableDatabase();
         /**
          * 獲取可寫的數據庫鏈接
          * 數據庫文件不存在時,會建立數據庫文件,而且執行onCreate()方法
          * 數據庫文件存在,且版本沒有改變時,不執行任何方法
          * 數據庫文件存在,版本提高,執行onUpdate方法
          */
     }
     public void testInsert(){
         PersonDAO personDAO = new PersonDAO(getContext());
         long rows = personDAO.insert(new Person("KKK",20000));
         System.out.println(rows);
     }
     public void testDelete(){
         PersonDAO personDAO = new PersonDAO(getContext());
         personDAO.delete(104);
     }
     public void testUpdate(){
         PersonDAO personDAO = new PersonDAO(getContext());
         personDAO.update(new Person(1,"www",30000));
     }
     public void testQuery(){
         PersonDAO personDAO = new PersonDAO(getContext());
         System.out.println(personDAO.query(5));
     }
     public void testFindAll(){
         PersonDAO personDAO = new PersonDAO(getContext());
         List<Person> persons = personDAO.findAll();
         for (Person p : persons) {
            System.out.println(p);
        }
     }
     public void testQueryCount(){
         PersonDAO personDAO = new PersonDAO(getContext());
         int count = personDAO.queryCount();
         System.out.println(count);
     }
     public void testQueryPage(){
         PersonDAO personDAO = new PersonDAO(getContext());
         List<Person> persons = personDAO.queryPage(3, 20);
         for (Person p : persons) {
            System.out.println(p);
        }
     }
     
}
TestSQLite.java測試類

運行結果:

二.內容提供者(ContentProvider)
1.什麼是ContentProvider
ContentProvider能夠用來把程序中的數據對外進行共享, 提供增刪改查的方法
ContentProvider中能夠註冊觀察者, 監聽數據的變化
* 2.怎麼建立?

步驟1:在清單文件AndroidManifest.xml中註冊

步驟2:定義類繼承ContentProvider

package com.shellway.sqlite.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;

public class SQLiteProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        System.out.println("query");
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        System.out.println("insert");
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        System.out.println("delete");
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        System.out.println("update");
        return 0;
    }
    
    @Override
    public String getType(Uri uri) {
        return null;
    }
}
定義類SQLiteProvider繼承ContentProvider

步驟3:另建立一個工程訪問內容提供者

package com.shellway.other;

import android.support.v7.app.ActionBarActivity;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //獲取解析器對象
        ContentResolver resolver = getContentResolver();
        //訪問內容提供者
        ContentValues values = new ContentValues();
        Uri uri = Uri.parse("content://com.shellway.sqlite.provider");
        resolver.insert(uri, values);
        resolver.delete(uri, null, null);
        resolver.update(uri, values, null, null);
        resolver.query(uri, null, null, null, null);
    }
}
MainActivity


3.在手機上註冊
將應用安裝到手機上便可, 不用運行程序
* 4.怎麼訪問
獲取解析器ContentResolver, 指定Uri
經過ContentResolver.insert(), delete(), update(), query()方法訪問Uri關聯的ContentProvider
5.Uri的處理
使用UriMatcher能夠檢查傳入的Uri是否和指定的匹配
若是Uri帶了id, 可使用ContentUris獲取id, 插入方法可使用ContentUris給Uri加上id

練習:

package com.shellway.sqlite.provider;

import com.shellway.sqlite.dao.DBSQLiteHelper;

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;

public class SQLiteProvider extends ContentProvider {
     private UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
     private DBSQLiteHelper helper;
     private static final int PERSON = 1;
     private static final int PERSON_ID = 2;
    @Override
    public boolean onCreate() {
        helper = new DBSQLiteHelper(getContext());
        //設置一個Uri,若是匹配到person,則返回PERSON
        matcher.addURI("com.shellway.sqlite.provider", "person", PERSON);
        matcher.addURI("com.shellway.sqlite.provider", "person/#", PERSON_ID);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = helper.getReadableDatabase();
        switch (matcher.match(uri)) {
        case PERSON_ID:
             long id = ContentUris.parseId(uri);
             selection = selection==null ? "id=" + id : selection + " AND id =" + id ;
        case PERSON:
            return db.query("people", projection, selection, selectionArgs, null, null, sortOrder);
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = helper.getWritableDatabase();
        switch (matcher.match(uri)) {
        case PERSON:
            long id = db.insert("people", "id", values);
            return ContentUris.withAppendedId(uri, id);
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }
    

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = helper.getWritableDatabase();
        switch (matcher.match(uri)) {
        case PERSON_ID:
             long id = ContentUris.parseId(uri);
             selection = selection==null ? "id=" + id : selection + " AND id =" + id ;
        case PERSON:
            return db.delete("people", selection, selectionArgs);
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        SQLiteDatabase db = helper.getWritableDatabase();
        switch (matcher.match(uri)) {
        case PERSON_ID:
             long id = ContentUris.parseId(uri);
             selection = selection==null ? "id=" + id : selection + " AND id =" + id ;
        case PERSON:
            return db.update("people", values, selection, selectionArgs);
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }
    
    @Override
    public String getType(Uri uri) {
        return null;
    }
}
02.SQLlite工程中的內容提供者SQLiteProvider
package com.shellway.other;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;

public class ProviderTest extends AndroidTestCase {
   public void test1(){
        //獲取解析器對象
        ContentResolver resolver = getContext().getContentResolver();
        //訪問內容提供者
        ContentValues values = new ContentValues();
        Uri uri = Uri.parse("content://com.shellway.sqlite.provider");
        
        resolver.insert(uri, values);
        resolver.delete(uri, null, null);
        resolver.update(uri, values, null, null);
        resolver.query(uri, null, null, null, null);
   }
   
   public void testQuery(){
       ContentResolver resolver = getContext().getContentResolver();
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person");
       Cursor c = resolver.query(uri, null, "balance>?", new String[]{8000+""}, "balance ASC");
       while (c.moveToNext()) {
          Person p = new Person(c.getInt(0),c.getString(1),c.getInt(2));
          System.out.println(p);
       }
   }
   public void testQuery2(){
       ContentResolver resolver = getContext().getContentResolver();
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person/10");
       Cursor c = resolver.query(uri, null, "balance>?", new String[]{8000+""}, "balance ASC");
       while (c.moveToNext()) {
          Person p = new Person(c.getInt(0),c.getString(1),c.getInt(2));
          System.out.println(p);
       }
   }
   public void testInsert(){
       ContentResolver resolver = getContext().getContentResolver();
       ContentValues values = new ContentValues();
       values.put("name", "Insert");
       values.put("balance", "54321");
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person");
       Uri count = resolver.insert(uri, values);
          System.out.println(count);
   }
   public void testUpdate(){
       ContentResolver resolver = getContext().getContentResolver();
       ContentValues values = new ContentValues();
       values.put("name", "Update");
       values.put("balance", "12345");
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person/106");
       int i = resolver.update(uri, values, null, null);
          System.out.println(i);
   }
   public void testDelete(){
       ContentResolver resolver = getContext().getContentResolver();
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person/107");
       int i = resolver.delete(uri, null, null);
          System.out.println(i);
   }
}
03.Other測試工程中的測試內容提供者的類ProviderTest

 細節補充:

    @Override
    public String getType(Uri uri) {
        switch (matcher.match(uri)) {
        case PERSON_ID:
             //通常返回的類型是:minetype? image/jpg  html/text css/text
             return "vnd.android.cursor.item/person"; //這裏表示返回的是單條的person數據
        case PERSON:
            return "vnd.android.cursor.dir/person";//這裏表示返回的是多條的person數據
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }
SQLiteProvider中的getType
   public void testType(){
       ContentResolver resolver = getContext().getContentResolver();
       String s1 = resolver.getType(Uri.parse("content://com.shellway.sqlite.provider/person/106"));
       String s2 = resolver.getType(Uri.parse("content://com.shellway.sqlite.provider/person"));
       System.out.println(s1);
       System.out.println(s2);
   }
ProviderTest中的測試getType方法:testType

注意1:ProviderTest類中的ContentResolver resolver = getContext().getContentResolver();這一行不能放到類的成員變量裏邊,由於:.class ->.dex ->.app ->安裝 ->開啓進程(開啓主線程)->建立ProviderTest對象 ->setContext ->測試方法 ->getConTest。不然會出現空指針異常,由於尚未setContext就getContext.

注意2:SQLiteProvider中的onCreate() 方法是在第一次啓動時執行,而後會長期駐留在後臺,除非是被殺死,不然不會再執行。

 

6.註冊觀察者
在應用程序中能夠對ContentProvider註冊一個觀察者(ContentObserver)
定義類繼承ContentObserver, 重寫onChange()方法
使用ContentResolver.registerContentObserver(Uri, boolean, ContentObServer)方法能夠註冊, 傳入指定Uri, 是否監聽子級路徑, 和一個觀察者對象
在收到數據改變通知以後, 會自動執行onChange()方法
7.通知觀察者
註冊觀察者以後, 須要在ContentProvider中進行通知, 觀察者才能收到, 使用ContentResolver.notifyChange()方法能夠通知數據的改變

練習:

package com.shellway.sqlite.ui;

import java.util.List;

import com.shellway.sqlite.R;
import com.shellway.sqlite.dao.PersonDAO;
import com.shellway.sqlite.domain.Person;

import android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat;
import android.support.v7.app.ActionBarActivity;
import android.content.ContentProvider;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class BaseAdapterActivity extends ActionBarActivity {

    private ListView lv;
    private List<Person> persons;
    private PersonDAO dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.id_LV); //獲取ListView
        dao = new PersonDAO(this);
        persons = dao.findAll();
        //給ListView添加Adapter,按照Adapter中的方法對ListView添加條目
        lv.setAdapter(new myAdapter()); 
        //給ListView添加條目點擊監聽器
        lv.setOnItemClickListener(new myOnClickListener());
        //註冊一個內容觀察者
        Uri uri = Uri.parse("content://com.shellway.sqlite.provider");
        //第二個參數表示監聽上面uri子路徑下全部的變化,若改成false則只監聽uri自己的變化
        getContentResolver().registerContentObserver(uri , true, new MyContentObserver());
    }
    private class MyContentObserver extends ContentObserver{
        public MyContentObserver() {
            super(new Handler());//Handler()是一個處理器,目前沒有用到
        }
        @Override
        public void onChange(boolean selfChange) {
            persons = dao.findAll();
            lv.setAdapter(new myAdapter()); 
        }
    }
    
    private class myOnClickListener implements OnItemClickListener{
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            //獲取點擊的條目上的數據,其內部其實是調用:myAdapter.getItem()
              Person p = (Person) parent.getItemAtPosition(position);
              Toast.makeText(getApplicationContext(), p.getBalance()+"", Toast.LENGTH_SHORT).show();
        }
    }
    
    //定義Adapter,把每一個Person對象生成一個條目,將全部條目裝入ListView
    private class myAdapter extends BaseAdapter{

        @Override
        public int getCount() {  //返回ListView中要裝入的條目的數量
            return persons.size();
        }

        @Override
        public Object getItem(int position) {//點哪一個條目就返回哪一個條目的對象
            return persons.get(position);
        }

        @Override
        public long getItemId(int position) {//返回條目的ID
            return position;
        }

        @Override
        //返回指定位置上的View,會被添加到ListView中(即一個Person構建成一個View,而後掛到ListView)
        public View getView(int position, View convertView, ViewGroup parent) {
            Person p = persons.get(position);
            //構建成一個條目(View),第三個參數是要掛到誰身上,這裏寫null它會自動返回到LListView中
            View item = View.inflate(getApplicationContext(), R.layout.item, null);
            TextView idTV = (TextView) item.findViewById(R.id.idTV);
            TextView nameTV = (TextView) item.findViewById(R.id.nameTV);
            TextView balanceTV = (TextView) item.findViewById(R.id.balanceTV);
            idTV.setText(p.getId()+"");
            nameTV.setText(p.getName());
            balanceTV.setText(p.getBalance()+"");
            return item;
        }
    }
}
02.SQLite工程中在BaseAdapterActivity裏註冊觀察者觀察一個Uri
package com.shellway.sqlite.provider;

import com.shellway.sqlite.dao.DBSQLiteHelper;

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;

public class SQLiteProvider extends ContentProvider {
     private UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
     private DBSQLiteHelper helper;
     private static final int PERSON = 1;
     private static final int PERSON_ID = 2;
    @Override
    public boolean onCreate() {
        helper = new DBSQLiteHelper(getContext());
        //設置一個Uri,若是匹配到person,則返回PERSON
        matcher.addURI("com.shellway.sqlite.provider", "person", PERSON);
        matcher.addURI("com.shellway.sqlite.provider", "person/#", PERSON_ID);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = helper.getReadableDatabase();
        switch (matcher.match(uri)) {
        case PERSON_ID:
             long id = ContentUris.parseId(uri);
             selection = selection==null ? "id=" + id : selection + " AND id =" + id ;
        case PERSON:
            return db.query("people", projection, selection, selectionArgs, null, null, sortOrder);
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = helper.getWritableDatabase();
        switch (matcher.match(uri)) {
        case PERSON:
            long id = db.insert("people", "id", values);
            getContext().getContentResolver().notifyChange(uri, null);
            return ContentUris.withAppendedId(uri, id);
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }
    

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = helper.getWritableDatabase();
        switch (matcher.match(uri)) {
        case PERSON_ID:
             long id = ContentUris.parseId(uri);
             selection = selection==null ? "id=" + id : selection + " AND id =" + id ;
        case PERSON:
            int count = db.delete("people", selection, selectionArgs);
            getContext().getContentResolver().notifyChange(uri, null);
            return count;
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        SQLiteDatabase db = helper.getWritableDatabase();
        switch (matcher.match(uri)) {
        case PERSON_ID:
             long id = ContentUris.parseId(uri);
             selection = selection==null ? "id=" + id : selection + " AND id =" + id ;
        case PERSON:
            int count = db.update("people", values, selection, selectionArgs);
            getContext().getContentResolver().notifyChange(uri, null);
            return count;
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }
    
    @Override
    public String getType(Uri uri) {
        switch (matcher.match(uri)) {
        case PERSON_ID:
             //通常返回的類型是:minetype? image/jpg  html/text css/text
             return "vnd.android.cursor.item/person"; //這裏表示返回的是單條的person數據
        case PERSON:
            return "vnd.android.cursor.dir/person";//這裏表示返回的是多條的person數據
        default:
            throw new RuntimeException("Uri不能試看識別。。。 ");
        }
    }
}
02.SQLite工程中在SQLiteProvider內容提供者裏編寫內容變動通知語句
package com.shellway.other;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;

public class ProviderTest extends AndroidTestCase {
   public void test1(){
        //獲取解析器對象
        ContentResolver resolver = getContext().getContentResolver();
        //訪問內容提供者
        ContentValues values = new ContentValues();
        Uri uri = Uri.parse("content://com.shellway.sqlite.provider");
        
        resolver.insert(uri, values);
        resolver.delete(uri, null, null);
        resolver.update(uri, values, null, null);
        resolver.query(uri, null, null, null, null);
   }
   
   public void testQuery(){
       ContentResolver resolver = getContext().getContentResolver();
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person");
       Cursor c = resolver.query(uri, null, "balance>?", new String[]{8000+""}, "balance ASC");
       while (c.moveToNext()) {
          Person p = new Person(c.getInt(0),c.getString(1),c.getInt(2));
          System.out.println(p);
       }
   }
   public void testQuery2(){
       ContentResolver resolver = getContext().getContentResolver();
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person/10");
       Cursor c = resolver.query(uri, null, "balance>?", new String[]{8000+""}, "balance ASC");
       while (c.moveToNext()) {
          Person p = new Person(c.getInt(0),c.getString(1),c.getInt(2));
          System.out.println(p);
       }
   }
   public void testInsert(){
       ContentResolver resolver = getContext().getContentResolver();
       ContentValues values = new ContentValues();
       values.put("name", "Test5");
       values.put("balance", "12345");
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person");
       Uri count = resolver.insert(uri, values);
   }
   public void testUpdate(){
       ContentResolver resolver = getContext().getContentResolver();
       ContentValues values = new ContentValues();
       values.put("name", "shellway");
       values.put("balance", "10000");
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person/116");
       int i = resolver.update(uri, values, null, null);
   }
   public void testDelete(){
       ContentResolver resolver = getContext().getContentResolver();
       Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person/122");
       int i = resolver.delete(uri, null, null);
   }
   public void testType(){
       ContentResolver resolver = getContext().getContentResolver();
       String s1 = resolver.getType(Uri.parse("content://com.shellway.sqlite.provider/person/106"));
       String s2 = resolver.getType(Uri.parse("content://com.shellway.sqlite.provider/person"));
       System.out.println(s1);
       System.out.println(s2);
   }
}
在A應用(03.Other)中使用內容提供者,使得數據發生改變
package com.shellway.contentobserver;

import android.support.v7.app.ActionBarActivity;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Uri uri = Uri.parse("content://com.shellway.sqlite.provider");
        getContentResolver().registerContentObserver(uri , true, new MyContentOberver());
    }
    private class MyContentOberver extends ContentObserver{
        public MyContentOberver() {
            super(new Handler());
        }
        @Override
        public void onChange(boolean selfChange) {
            Uri uri = Uri.parse("content://com.shellway.sqlite.provider/person");
            Cursor c = getContentResolver().query(uri, null, null, null, "id desc limit 1");
            while (c.moveToNext()) {
                Toast.makeText(getApplicationContext(), c.getString(1), Toast.LENGTH_SHORT).show();
            }
        }
    }
}
在B應用(04.ContentObserver)中也註冊一個觀察者觀察相同的Uri,若該Uri上的數據發生改變,我會收到通知而後執行個人onChange方法

結果:一旦在A應用中經過內容提供者改變數據,則註冊在該Uri上的觀察者都會收到數據發生改變的通知,由於事先在內容提供者裏都已經放了一個「通知者」,這裏的通知者便是:getContext().getContentResolver().notifyChange(uri, null);因此,SQLite工程和B應用中的觀察者都會接收到通知,從而執行本身的onChange()方法。


四.監聽短信
1.獲取源碼
安裝GIT工具:
在網站上下載com.android.providers.telephony源碼:https://github.com/android
經過清單文件能夠查找到Uri
2.監聽改變
對指定Uri添加ContentOberver
在onChange方法中查詢最新的記錄, 收發短信時都會收到修改通知, 這樣就能獲取剛剛收發的短信了

package com.shellway.smsobserver;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.support.v7.app.ActionBarActivity;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;

public class MainActivity extends ActionBarActivity {

    private Uri uri;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //註冊短信觀察者
        uri = Uri.parse("content://sms");
        getContentResolver().registerContentObserver(uri , true, new MyObserver());
    }
    private class MyObserver extends ContentObserver{

        private long flag;
        public MyObserver() {
            super(new Handler());
        }
        @Override
        public void onChange(boolean selfChange) {
            ContentResolver resolver = getContentResolver();
            //查詢最新的一條短信信息,由於收發短信,信息都會先往數據庫存而後才顯示在手機屏幕
            Cursor c = resolver.query(uri, null, null, null, "_id desc limit 1");
            while(c.moveToNext()){
                String addr = c.getString(c.getColumnIndex("address"));
                String body = c.getString(c.getColumnIndex("body"));
                int type = c.getInt(c.getColumnIndex("type"));
                Long date = c.getLong(c.getColumnIndex("date"));
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                Date d = new Date(date);
                String dd = sdf.format(d);
                if(flag!=date){ //由於回短信時會打印出三條重複的信息,這裏利用時間來控制打印結果只爲一條信息
                System.out.println(dd +" " + (type == 1 ? "收":"發") + addr +" "+ body);
                flag = date;
                }
            }
        }
    }
}
監聽短信信息變化:MainActivity.java
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.shellway.smsobserver"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
    <uses-permission  android:name="android.permission.READ_SMS"/>
    <uses-permission  android:name="android.permission.WRITE_SMS"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
AndroidManifest.xml

 結果:

五.讀寫聯繫人
1.獲取原碼
和監聽短信相同, 獲取com.android.providers.contacts源碼
2.讀取聯繫人
先讀raw_contacts表中的id, 在根據id查找data表
3.寫出聯繫人
先向raw_contacts表中寫出一個id(自動生成)
在向data表寫出3條對應數據, raw_contact_id一列使用剛剛插入的id

 練習:(讀聯繫人)

1.新建一個工程:

2.分析:

3.編寫程序:

package com.shellway.contacts;

import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;

public class ContactsTest extends AndroidTestCase {
    
    public void testContexts(){
     Uri idUri = Uri.parse("content://com.android.contacts/raw_contacts");
     Uri dataUri = Uri.parse("content://com.android.contacts/data");
     ContentResolver resolver = getContext().getContentResolver();
     Cursor c = resolver.query(idUri, new String[]{"_id"}, null, null, null);
    /* String[] arr = c.getColumnNames();//打印raw_contacts表中的全部列名
     for (String s : arr) {
        System.out.println(s);
      }*/
     while(c.moveToNext()){
         int idRaw = c.getInt(0); 
         Cursor datac = resolver.query(dataUri, new String[]{"mimetype","data1","data2","data3"}
                               , "raw_contact_id=?"
                               , new String[]{idRaw+""}
                               , null);
         while(datac.moveToNext()){
             if(datac.getString(0).equals("vnd.android.cursor.item/name")){
                 System.out.println("姓名: "+ datac.getString(datac.getColumnIndex("data1")));
             }else if(datac.getString(0).equals("vnd.android.cursor.item/phone_v2")){
                 System.out.println("電話: "+ datac.getString(datac.getColumnIndex("data1")));
             }else if(datac.getString(0).equals("vnd.android.cursor.item/email_v2")){
                 System.out.println("郵箱: "+ datac.getString(datac.getColumnIndex("data1")));
             }
         }
     }
  /*   Cursor datac = resolver.query(dataUri, null, null, null, null);//打印data表中的全部列名
     String[] s = datac.getColumnNames();
     for (String st : s) {
        System.out.println(st);
    }*/
     
   } 
}
ContactsTest.java
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.shellway.contacts"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
        <instrumentation
        android:targetPackage="com.shellway.contacts"
        android:name="android.test.InstrumentationTestRunner" />
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
     <uses-library android:name="android.test.runner" />
    </application>

</manifest>
AndroidManifest.xml

 結果:

相關文章
相關標籤/搜索