*********************************************2012-11-23****************************************************
十一、Content provider内容提供者控件
1、作用:内容提供者为数据共享提供统一接口,也是一个常用的控件
2、配置:
a、创建内容提供者类继承ContentProvider类的,并覆写抽象方法
b、配置ContentProvider,在提供方的应用的AndroidManifest.xml中添加配置
3、uri
content://cn.itcast.provider/person/10
代表含义:scheme(固定)// 主机名或authority /路径(数据)
4、编码实现通过内容提供者给外界程序提供操作数据的接口
a、内容提供者实现类:UserProvider
package caiz.android.dboper;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import caiz.android.dboper.service.DBOpenHelper;
/**
* 内容提供者访问数据库
* @author HuangYucai
*
*/
public class UserProvider extends ContentProvider {
private DBOpenHelper dbOpenHelper;
private static final UriMatcher MATCHER = new UriMatcher(
UriMatcher.NO_MATCH);
private static final int INSERTUSER = 1;
private static final int DELETEUSER = 2;
static {
MATCHER.addURI("com.caiz.android.providers.userProvider", "user",
INSERTUSER);
MATCHER.addURI("com.caiz.android.providers.userProvider", "user/#",
DELETEUSER);
}
@Override
public boolean onCreate() {// 当内容提供者创建时自动调用
dbOpenHelper = new DBOpenHelper(this.getContext());
// TODO Auto-generated method stub
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
Cursor cursor = null;
switch (MATCHER.match(uri)) {
case 1:
cursor = db.query("user", projection, selection, selectionArgs,
null, null, sortOrder);
return cursor;
case 2:
long rowid = ContentUris.parseId(uri);
String where = "uid=" + rowid;
if (selection != null && !"".equals(selection.trim())) {
where = where + " and " + selection;
}
cursor = db.query("user", projection, where, selectionArgs, null,
null, sortOrder);
return cursor;
default:
throw new IllegalArgumentException("The uri'" + uri
+ "' is illegal!");
}
}// 供外部应用查询内容提供者的数据
@Override
public String getType(Uri uri) {// 返回操作数据的类型
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {// 供外部应用插入内容提供者的数据
// 判断uri专门类
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
switch (MATCHER.match(uri)) {
case 1:
long rowid = db.insert("user", "uname", values);
Uri insertUri = ContentUris.withAppendedId(uri, rowid);
return insertUri;
default:
throw new IllegalArgumentException("The uri'" + uri
+ "' is illegal!");
}
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {// 供外部应用删除内容提供者的数据
// 判断uri专门类
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
int rowCounts = 0;
switch (MATCHER.match(uri)) {
case 1:
rowCounts = db.delete("user", selection, selectionArgs);
break;
case 2:
long rowid = ContentUris.parseId(uri);
String where = "uid=" + rowid;
if (selection != null && !"".equals(selection.trim())) {
where = where + " and " + selection;
}
rowCounts = db.delete("user", where, selectionArgs);
break;
default:
throw new IllegalArgumentException("The uri'" + uri
+ "' is illegal!");
}
return rowCounts;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {// 供外部应用更新内容提供者的数据
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
int rowCounts = 0;
switch (MATCHER.match(uri)) {
case 1:
rowCounts = db.update("user", values, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("The uri'" + uri
+ "' is illegal!");
}
return rowCounts;
}
}
b、内容通过者的测试类:ContentProviderTest
package caiz.android.xml.test;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;
/**
* 内容提供者测试类
* @author HuangYucai
*
*/
public class ContentProviderTest extends AndroidTestCase {
public void testInsert()throws Exception{//测试添加
Uri uri=Uri.parse("content://com.caiz.android.providers.userProvider/user");
ContentResolver resolver=this.getContext().getContentResolver();
ContentValues values=new ContentValues();
values.put("uname", "tqiongqiong");
values.put("phone", "1523798091");
values.put("amount", "5000001");
resolver.insert(uri, values);
}
public void testDelete()throws Exception{//测试删除
Uri uri=Uri.parse("content://com.caiz.android.providers.userProvider/user/44");
ContentResolver resolver=this.getContext().getContentResolver();
int i=resolver.delete(uri, null, null);
Log.i("ContentProvider", "删除了"+i+"条记录");
}
public void testUpdate()throws Exception{//测试更新
Uri uri=Uri.parse("content://com.caiz.android.providers.userProvider/user/");
ContentResolver resolver=this.getContext().getContentResolver();
ContentValues values=new ContentValues();
values.put("uname", "tangqiongqiong");
values.put("amount", "5000002");
int i=resolver.update(uri, values, "uid=?", new String[]{"45"});
Log.i("ContentProvider", "更新了"+i+"条记录");
}
public void testQueryList()throws Exception{//测试查询列表
Uri uri=Uri.parse("content://com.caiz.android.providers.userProvider/user/");
ContentResolver resolver=this.getContext().getContentResolver();
Cursor cursor= resolver.query(uri, null, "uid>?", new String[]{"20"}, "uid desc");
int num=0;
while(cursor.moveToNext()){
String uname= cursor.getString(cursor.getColumnIndex("UNAME"));
Log.i("ContentProvider", "用户"+(++num)+"的姓名:"+uname);
}
}
public void testQueryById()throws Exception{//测试查询单个
Uri uri=Uri.parse("content://com.caiz.android.providers.userProvider/user/");
ContentResolver resolver=this.getContext().getContentResolver();
Cursor cursor= resolver.query(uri, null, "uid=?", new String[]{"45"}, "uid desc");
if(cursor.moveToNext()){
String uname= cursor.getString(cursor.getColumnIndex("UNAME"));
Log.i("ContentProvider", "id为45的用户姓名是:"+uname);
}
}
}
***********************************************************************************************************
*************************************************2012-11-24************************************************
十一、监听Content provider内容提供者的数据变化
1、作用:两个应用操作使用同一个内容提供者的数据,A应用改变了内容提供者数据,必须通知B应用内容提供者数据
已经改变
A应用---添加数据---》内容提供者---》发出数据变化通知---》B应用(做出响应)
原理:观察者设计模式的应用
2、代码实践:
a、A应用在界面中添加一个按钮,并设置单击事件:
android:layout_height="fill_parent"
android:orientation="vertical" >
public class AAppActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
//点击按钮时执行的插入数据命令
public void insert(View v) {
Uri uri=Uri.parse("content://com.caiz.android.providers.userProvider/user");
ContentResolver resolver =this.getContentResolver();
ContentValues values=new ContentValues();
values.put("uname", "A_App insert CaiZ");
values.put("phone", "123456789");
values.put("amount", "70000");
resolver.insert(uri, values);
}
}
b、在内容提供者应用的添加数据方法中添加内容更新通知
@Override
public Uri insert(Uri uri, ContentValues values) {// 供外部应用插入内容提供者的数据
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
switch (MATCHER.match(uri)) {
case 1:
long rowid = db.insert("user", "uname", values);
Uri insertUri = ContentUris.withAppendedId(uri, rowid);
//设置数据更新通知(对于某个uri)
this.getContext().getContentResolver().notifyChange(uri, null);
return insertUri;
default:
throw new IllegalArgumentException("The uri'" + uri
+ "' is illegal!");
}
}
c、在应用B中添加应用的事件监听处理方法
package com.caiz.android.bapp;
import android.app.Activity;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
public class BAppActivity extends Activity {
/** Called when the activity is first created. */
public static final String TAG = "BApp";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Uri uri = Uri.parse("content://com.caiz.android.providers.userProvider/user");
// 注册内容观察者
this.getContentResolver().registerContentObserver(uri, true,
new UserContentObserver(new Handler()));
}
// 内容观察者内部类(继承观察者内部类)
public class UserContentObserver extends ContentObserver {
//构造方法
public UserContentObserver(Handler handler) {
super(handler);
}
// (覆写)数据改变时候调用的方法
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.i(TAG, "OK=OK");
Uri uri = Uri
.parse("content://com.caiz.android.providers.userProvider/user");
Cursor cursor = getContentResolver().query(uri, null, null, null,
"uid desc limit 1");
if (cursor.moveToFirst()) {// 查询出最新记录并打印出来
String uname = cursor.getString(cursor.getColumnIndex("UNAME"));
Log.i(TAG, "uname=" + uname);
}
}
}
}
***********************************************************************************************************
**********************************************2012-11-25***************************************************
十二、访问和添加通讯录内容
1、作用:有些应用要求访问或添加通讯录操作
2、添加权限,在清单文件中添加读写通讯录的权限:
3、代码实现:
/**
* 存取通讯录中信息内容
* @author HuangYucai
*/
public class ContactsTest extends AndroidTestCase {
private String TAG="ContactsTest";
// 测试获取通讯录
public void testGetContacts()throws Exception {
StringBuilder sb=new StringBuilder("DATA:");
Uri uri = Uri.parse("content://com.android.contacts/contacts");
ContentResolver resolver = this.getContext().getContentResolver();
Cursor cursor = resolver.query(uri, new String[] { "_id" }, null, null,
null);
while (cursor.moveToNext()) {
String id=cursor.getString(0);
uri = Uri.parse("content://com.android.contacts/contacts/"+id+"/data");
sb.append("id=").append(id);
resolver = this.getContext().getContentResolver();
Cursor c = resolver.query(uri, new String[] { "data1","data2","mimetype" }, null, null,null);
while(c.moveToNext()){
String type=c.getString(c.getColumnIndex("mimetype"));
String data=c.getString(c.getColumnIndex("data1"));
if(type.equals("vnd.android.cursor.item/name")){
sb.append("name=").append(data);
}
if(type.equals("vnd.android.cursor.item/email_v2")){
sb.append("email=").append(data);
}
if(type.equals("vnd.android.cursor.item/phone_v2")){
sb.append("phone=").append(data);
}
}
}
Log.i(TAG,sb.toString());
}
//测试通过电话号码查询联系人
public void testgetNameByPhone() throws Exception{
StringBuilder sb=new StringBuilder("DATA:");
String number="13533415878";
Uri uri=Uri.parse("content://com.android.contacts/data/phones/filter/"+number);
ContentResolver resolver =this.getContext().getContentResolver();
Cursor cursor=resolver.query(uri, new String[]{"display_name"}, null, null, null);
if(cursor.moveToFirst()){
sb.append("name=").append(cursor.getString(0));
}
Log.i(TAG,sb.toString());
}
//测试通过电话号码查询联系人
public void testAddContacts() throws Exception{
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts/");
ContentResolver resolver =this.getContext().getContentResolver();
ContentValues values =new ContentValues();
long rowid=ContentUris.parseId(resolver.insert(uri, values));
uri=Uri.parse("content://com.android.contacts/data/");
values.put("raw_contact_id", rowid);
values.put("mimetype", "vnd.android.cursor.item/name");
values.put("data2", "黄育才");
resolver.insert(uri, values);
values.clear();
values.put("raw_contact_id", rowid);
values.put("mimetype", "vnd.android.cursor.item/phone_v2");
values.put("data2", "2");
values.put("data1", "12121212");
resolver.insert(uri, values);
values.clear();
values.put("raw_contact_id", rowid);
values.put("mimetype", "vnd.android.cursor.item/email_v2");
values.put("data2", "2");
values.put("data1", "[email protected]");
resolver.insert(uri, values);
}
//测试通过电话号码查询联系人(带事务处理的方法)
public void testAddContactsWithTransaction() throws Exception{
ArrayList
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts/");
ContentResolver resolver =this.getContext().getContentResolver();
ContentProviderOperation op1=ContentProviderOperation.newInsert(uri)
.withValue("account_name", null)
.build();
operations.add(op1);
uri=Uri.parse("content://com.android.contacts/data/");
ContentProviderOperation op2=ContentProviderOperation.newInsert(uri)
.withValueBackReference("raw_contact_id", 0)
.withValue("mimetype", "vnd.android.cursor.item/name")
.withValue("data2", "2")
.withValue("data1", "刘德华")
.build();
operations.add(op2);
ContentProviderOperation op3=ContentProviderOperation.newInsert(uri)
.withValueBackReference("raw_contact_id", 0)
.withValue("mimetype", "vnd.android.cursor.item/phone_v2")
.withValue("data2", "2")
.withValue("data1", "121212123")
.build();
operations.add(op3);
ContentProviderOperation op4=ContentProviderOperation.newInsert(uri)
.withValueBackReference("raw_contact_id", 0)
.withValue("mimetype", "vnd.android.cursor.item/email_v2")
.withValue("data2", "2")
.withValue("data1", "[email protected]")
.build();
operations.add(op4);
//执行事务方式的保存
resolver.applyBatch("com.android.contacts", operations);
}
}
***********************************************************************************************************
********************************************2012-11-26*****************************************************
十三、网络图片查看器
1、作用:将通过HTTP访问网络图片数据,并将图片数据在android手机应用中显示
2、思路:使用API
ImageView 类 的setImageBitmap(Bitmap bm)
通过URL类 构建一个HttpURLConnection实例
HttpURLConnection 类 getInputStream() 拿到数据流
IO操作把流转换成字节数组
3、实现过程及代码:
a、创建应用的界面,图片显示一般用ImageView控件
b、需要设置访问网络的权限
在清单文件中加入:
c、代码:
/**
* 读取网络图片的主类
* @author HuangYucai
*/
public class NetImageActivity extends Activity {
/** Called when the activity is first created. */
private Button bnt;
private ImageView imgview;
private EditText txtEdit;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtEdit=(EditText)this.findViewById(R.id.imagepath);
bnt=(Button)this.findViewById(R.id.bnt);
imgview=(ImageView)this.findViewById(R.id.image);
bnt.setOnClickListener(new BntOnclickListener());
}
//单机按钮的事件监听器实现类
public final class BntOnclickListener implements View.OnClickListener{
public void onClick(View v) {
String url=txtEdit.getText().toString().trim();//获取图片的路径
if(url!=null&&!"".equals(url)){
try {
byte[] data = ImageService.getImageDataByUrl(url);//获取图片的字节数组数据
Bitmap bm=BitmapFactory.decodeByteArray(data, 0, data.length);//Bitmap对象
imgview.setImageBitmap(bm);//设置图片显示
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "图片访问失败", Toast.LENGTH_SHORT).show();
}
}else{
Toast.makeText(getApplicationContext(), "请输入图片路径", Toast.LENGTH_SHORT).show();
}
}
}
}
/**
* 读取图片的service类
* @author HuangYucai
*/
public class ImageService {
public static byte[] getImageDataByUrl(String path) throws Exception {
URL url=new URL(path);//根据路径初始化URL对象
HttpURLConnection conn=(HttpURLConnection) url.openConnection();//根据URL获取HttpURLConnection
conn.setConnectTimeout(5000);//设置HttpURLConnection请求时间为5秒
conn.setRequestMethod("GET");//设置HttpURLConnection请求方式为“GET”
if(conn.getResponseCode()==200){//当请求状态为200,即为请求成功时则获取输入流
InputStream inStream=conn.getInputStream();//获取输入流
return StreamTool.readBytes(inStream);//处理输入流
}else{
throw new Exception();
}
}
}
/**
*输入流转换为字节数组的工具类
* @author HuangYucai
*/
public class StreamTool {
public static byte[] readBytes(InputStream inStream) throws Exception {
ByteArrayOutputStream bis=new ByteArrayOutputStream();//字节输出流对象
byte[] buffer=new byte[1024];
int len=0;
while((len=inStream.read(buffer))!=-1){//读到buffer
bis.write(buffer,0,len);//写buffer到字节输出流对象bis
}
return bis.toByteArray();//从内存中拿到然后转为字节数组返回
}
}
4、注意项
在访问本机的url时,一般用http://localhost:8080/web/me.jpg或者http://127.0.0.1:8080/web/me.jpg
但是,该环境中,android和windows是两个不同的系统,故不能用
而只能用本机的IP(局域网中的IP地址):如http://192.168.0.186:8080/web/me.jpg
备注:使用ipconfig命令查看本机IP
查看本机IP的方法:在开始——》搜索程序——》输入cmd——》输入ipconfig命令——》查看本机的IP地址
***********************************************************************************************************
********************************************2012-11-27*****************************************************
十四、Android获取html网页代码
1、通过Connection从网络上获取HTML代码,并显示在TextView控件中
2、步骤:
a、设计界面,为了让TextView可滚动,将其放在一个ScrollView控件中,这样文字就可以滚动了
android:layout_height="fill_parent"
>
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
b、代码:
/**
* 主程序类
* @author HuangYucai
*/
public class HtmlViewerActivity extends Activity {
/** Called when the activity is first created. */
private EditText pathText;
private Button viewBnt;
private TextView txtViewer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pathText= (EditText)this.findViewById(R.id.path);
viewBnt=(Button)this.findViewById(R.id.bnt);
txtViewer=(TextView)this.findViewById(R.id.viewer);
viewBnt.setOnClickListener(new BntOnclickListener());
}
public final class BntOnclickListener implements View.OnClickListener{
public void onClick(View v) {
String path=pathText.getText().toString();
String html;
try {//获取字符数据设置到TextView空间
html = PageService.getPageStr(path);
txtViewer.setText(html);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "获取网页失败", Toast.LENGTH_SHORT).show();
}
}
}
}
/**
*获取html代码数据的service类
* @author HuangYucai
*/
public class PageService {
public static String getPageStr(String path) throws Exception {
String html="";
URL url=new URL(path);
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if(conn.getResponseCode()==200){//请求状态成功时
InputStream inStream= conn.getInputStream();
byte[] data=StreamTool.getBytesByStream(inStream);
html=new String(data,"UTF-8");//网页编码格式为"UTF-8"
}
return html;
}
}
/**
* 流处理的工具类
* @author HuangYucai
*/
public class StreamTool {
public static byte[] getBytesByStream(InputStream inStream) throws Exception {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte[] buffer= new byte[1024];
int len=0;
while((len=inStream.read(buffer))!=-1){
baos.write(buffer,0,len);
}
return baos.toByteArray();
}
}
4、注意项
a、在访问本机的url时,一般用http://localhost:8080/web/index.jsp或者http://127.0.0.1:8080/web/index.jsp
但是,该环境中,android和windows是两个不同的系统,故不能用
而只能用本机的IP(局域网中的IP地址):如http://192.168.0.186:8080/web/index.jsp
b、在将字节数组转换为字符串数据时,要指定编码格式,而且要与网页的编码一致,否则出现乱码
***********************************************************************************************************