• 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, 指定数据的绑定关系

    练习一:

    <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

    运行结果:

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

    运行结果:

    二.内容提供者(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

     结果:

  • 相关阅读:
    MyEclipse中的几种查找方法
    WebLogic初学笔记
    CountDownLatch源码分析
    linux--句柄相关
    linux命令--wc
    Spring源码解析(九)--再来说说三级缓存
    定位JVM内存泄漏常用命令和方法
    Mybatis整合Spring之MapperFactoryBean怎么拿到的SqlSessionFactory
    Mybatis3.3.0 Po类有LocalDateTime字段报错
    时间范围查询优化技巧
  • 原文地址:https://www.cnblogs.com/shellway/p/4120088.html
Copyright © 2020-2023  润新知