java攻城狮之路(Android篇)--ListView与ContentProvider

时间:2024-03-31 11:33:50

一.ListView
1.三种Adapter构建ListView
ListView添加条目的时候, 可以使用setAdapter(ListAdapter)方法, 常用的ListAdapter有三种
BaseAdapter: 定义一个类继承BaseAdapter, 重写4个抽象方法, ListView的条目是由getView()方法构建出来的
SimpleAdapter: 创建SimpleAdapter对象时, 传入数据(List<Map<String, ?>>), 并指定数据的绑定关系
SimpleCursorAdapter: 创建SimpleCursorAdapter对象时, 传入一个Cursor, 指定数据的绑定关系

练习一:

java攻城狮之路(Android篇)--ListView与ContentProvider

<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:

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

        <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:

注意:使用SimpleCusorAdapter,在查询结果中要包含有“_id”这一列,这里我把id取别名为_id的方法解决。

    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

运行结果:

java攻城狮之路(Android篇)--ListView与ContentProvider

2.监听ListView的点击
调用ListView.setOnItemClickListener(OnItemClickListener)方法注册一个监听器
在监听器的onItemClick()方法中使用 parent.getItemAtPosition(position) 方法可以获取指定条目上的数据
BaseAdapter: 返回的就是自定义的getItem()方法中返回的数据
SimpleAdapter: 返回的是一个Map, 就是创建SimpleAdapter时List中的一个Map
SimpleCursorAdapter: 返回的是一个Cursor, 这个Cursor就是创建时传入的Cursor, 但是已经通过moveToPosition()方法指定到点击的索引了

练习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

辅助类:

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测试类

运行结果:

java攻城狮之路(Android篇)--ListView与ContentProvider

二.内容提供者(ContentProvider)
1.什么是ContentProvider
ContentProvider可以用来把程序中的数据对外进行共享, 提供增删改查的方法
ContentProvider中可以注册观察者, 监听数据的变化
* 2.怎么创建?

步骤1:在清单文件AndroidManifest.xml中注册

java攻城狮之路(Android篇)--ListView与ContentProvider

步骤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

结果:

java攻城狮之路(Android篇)--ListView与ContentProvider

五.读写联系人
1.获取原码
和监听短信相同, 获取com.android.providers.contacts源码
2.读取联系人
先读raw_contacts表中的id, 在根据id查找data表
3.写出联系人
先向raw_contacts表中写出一个id(自动生成)
在向data表写出3条对应数据, raw_contact_id一列使用刚刚插入的id

 练习:(读联系人)

1.新建一个工程:

java攻城狮之路(Android篇)--ListView与ContentProvider

2.分析:

java攻城狮之路(Android篇)--ListView与ContentProvider

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

结果:

java攻城狮之路(Android篇)--ListView与ContentProvider