Android 学习笔记之ContentProvider实现数据共享....

时间:2023-03-09 05:29:50
Android 学习笔记之ContentProvider实现数据共享....

PS:最近听老师说打算让我参与企业的app制作,让我加快学习的进度...好吧,貌似下周还有考试...貌似实验室这个app也要做...暂时不管了...那就只能加快进度了,感觉略微的有点激动和紧张,总算是可以开始对项目进行着手操作了...学的东西还是很少,还要继续努力啊...搞定Android的网络通信后就可以正式的进入项目开发了...不说废话了...

学习内容:

1.使用ContentProvider存储数据

2.操作联系人的ContentProvider...

3.多媒体信息的ContentProvider...

ContentProvider:

  ContentProvider类是一个实现数据共享的一个类,它将共享的数据进行包装,然后对外暴露接口,外界的应用程序就能通过接口来访问被封装的数据,从而达到数据共享的目的...使用这个类需要了解一些其他的东西...

Uri:

  在使用ContentProvider对数据进行操作的时候,以Uri的形式进行数据交换...Uri包含两个部分,一部分包含着我们要操作的ContentProvider..另一部分包括的是对ContentProvider中哪一个数据进行操作...

Uri uri=Uri.parse("content://com.example.contentprovider/person");//这个Uri表示访问person表中的所有记录...

UriMatcher:

  在使用ContentProvider类操作某一种方法的时候有可能传递多种Uri,必须对这些传递的Uri进行相应的判断才能够决定如何去操作...可以使用switch语句进行判断...

    UriMatcher match =new UriMatcher(No_MATCH);//对象的实例化操作...NO_MATCH表示-1...
match.addURI("包名","表名",匹配码)..
match.addURI("content://com.example.contentprovider","person",1);//增加一个URI值
/* 如果match方法匹配content://content.example.contentprovider/person/5
* 那么返回值就是2...
*/
mathc.addURI("content://com.example.contentprovider","person/#",2);//#为通配符......

ContentUris:

  由于所有的数据操作都要通过Uri的形式进行传递,那么当执行完增加操作之后,我们往往想要返回我们增加后数据的ID以Uri的形式进行返回,那么就可以使用这个类来完成操作...

数据共享:

  如果想实现数据共享,我们可以自己定义自己的ContentProvider...定义以后重写其内部的方法,不过这种方式一般都是没有任何的必要的..因为Android提供了多种类型的ContentProvider(图片,音频,视频,联系人等)...这些类都是它所提供的,因此我们只需要把数据封装这些类中,然后就可以完成数据的共享...因此一般我们都是将数据写入到系统提供的类中,完成数据的共享....

联系人的ContentProvider...

  一般当我们在打电话或者是发短信的时候会使用到联系人这一数据信息,因此这个联系人内部的数据信息必须要进行共享,才使得其他的应用程序获取联系人信息...因此我们需要把数据写入到ContentProvider中....我们在模拟器中或者是自己的手机中也可以,添加几条联系人...然后我们通过触发按钮的形式来获取我们保存的数据信息...这个还需要配置一下权限,在AndroidManifest.xml文件中加入<user-permission android:name="android.permission.READ_CONTACTS"/>....布局文件一个按钮,一个文本显示控件...很简单....主要还是实现过程...

import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.view.Menu;
import android.view.View;
import android.widget.TextView; public class MainActivity extends Activity implements View.OnClickListener { private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.but).setOnClickListener(this);
findViewById(R.id.but_1).setOnClickListener(this);
tv=(TextView) findViewById(R.id.text);
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.but:
StringBuilder st=getContents();//定义一个StringBuilder对象...表示st是一个可变的字符串...这里也可以使用StringBuffered...但是使用StringBuider更快...
tv.setText(st.toString());
break;
}
}
  private StringBuilder getContents(){
StringBuilder stlog=new StringBuilder();
ContentResolver cr=this.getContentResolver();//操作ContentProvider首先要利用getContentResolver()获取ContentResolver实例..
Cursor cursor=cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);//用Cursor来保存结果...
/* cr.query(uri, projection, selection, selectionArgs, sortOrder)
* uri参数:表示的是对哪个数据表进行操作..
* projection参数:表示在表中需要选取的列值..
* selection参数:表示的是查询的条件...相当于where子句..
* selectionArgs参数:表示语句中是否有?...
* sortorder参数:表示查询的结果按照什么形式进行排列...
* 查询的结果返回给Cursor对象...按行进行排列数据...
* */
for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()){
//这里cr按行来保存每一条获取的数据...我们可以对想要的数据进行一一获取..
int nameIndex=cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);//这句话的意思表示获取联系人的名字...内容在ContactsContract.Contacts中...
String name=cursor.getString(nameIndex);
stlog.append("name= "+name+";");
String contentid=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));//获取联系人的ID信息...
//由于一个人可能有多个手机号码...因此还需要Cursor对多个号码进行保存...ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = "+contenti 这一参数来限制必须是同一个ID下的电话号码..说白了就是限制号码必须是一个人的...
Cursor phonecursor=cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = "+contentid, null, null);
while(phonecursor.moveToNext()){
String strphone=phonecursor.getString(phonecursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
stlog.append("phone="+ strphone+";");
}
   // phonecursor.close(); 这句话在模拟器上可以使用...我们动态关闭...
//这个也一样可能有多个email....
Cursor email=cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = "+contentid, null, null);
while(email.moveToNext()){
String stremail=email.getString(email.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
stlog.append("email="+stremail+";");
}
/*
* if(Build.VERSION.SDK_INT < 14) {
* cursor.close();
* }
* Android真机超过4.0以后的版本无法使用close()方法来关闭程序...否则会出现崩溃现象... 但是在模拟器上可以运行... 可以使用上面的函数进行判断是否已经超过4.0版本...
* */
// email.close();
// cursor.close();
}
return stlog; } }
<LinearLayout  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:orientation="vertical"
tools:context=".MainActivity" > <TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/but"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="获取信息..."/>
<Button
android:id="@+id/but_1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="增加信息..."/> </LinearLayout>

  这里我们只是获取我们保存的数据信息,同时我们可以添加联系人,然后将数据保存在联系人中...插入数据就需要使用到ContentValues这个类,将插入的数据信息保存在其中...最后通过insert方法来完成数据的插入操作...这样就完成了数据的插入操作...

    Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
ContentResolver resolver_1=this.getContentResolver();
ContentValues values=new ContentValues();
//获取主键值...
long contactid=ContentUris.parseId(resolver_1.insert(uri, values));
uri=Uri.parse("content://com.android.contacts/data");
values.put("raw_contact_id",contactid);
values.put("mimetype", "vnd.android.cursor.item/name");
values.put("data2", "aa");
resolver_1.insert(uri, values);
values.clear();
values.put("raw_contact_id", contactid);
values.put("mimetype", "vnd.andoroid.cursor.item/phone_v2");
values.put("data2", "2");
values.put("data1", "1131313");
resolver_1.insert(uri, values);
values.clear();
values.put("raw_contact_id", contactid);
values.put("mimetype", "vnd.android.cursor.item/email_v2");
values.put("data2", "2");
values.put("data1", "sa@qq.com");
resolver_1.insert(uri, values);

多媒体信息的ContentProvider...

  多媒体的ContentProvider和联系人的基本都差不多,基本的模式都差不多,多媒体的ContentProvider也是需要首先获取ContentValues实例..然后才能进行增删改查等操作...查询一般使用query(uri,Prjs,Selections,selectArgs,Order)..方法来查询然后进行保存...查询的URI接收几个系统参数...这几个系统参数表示的是几个URI,这几个URI分别表示的是存储在手机内部或者是外部的图片内容,音频内容,或者是视频内容的URI...通过传递参数,我们就可以获取到手机里的图片,音频,或者是视频...

  通过一个简单的例子来说一下多媒体信息的ContentProvider...然后实现多媒体数据信息的共享...这个例子就是获取手机里的音乐的基本信息...主布局...

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
tools:context=".MainActivity" > <TextView
android:id="@+id/msg"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:text="所有音乐"
android:textSize="20dp"
android:gravity="center"/>
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableRow >
<TextView
android:layout_height="wrap_content"
android:layout_width="150px"
android:textSize="15px"
android:text="歌曲名"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="100px"
android:textSize="15px"
android:text="歌手"/>
<TextView
android:layout_width="50px"
android:layout_height="wrap_content"
android:textSize="15px"
android:text="时间"/>
</TableRow>
</TableLayout>
<ListView
android:id="@+id/songlist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"> </ListView> </LinearLayout>

  这个布局没什么好说的...重点还是如何实现获取音乐的基本信息...这是实现的过程...在这里调用了另一个布局文件...调用另一个布局文件来显示获取到的数据信息...这种方式非常的常用...另一个布局文件...

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableRow >
<TextView
android:id="@+id/title"
android:layout_height="wrap_content"
android:layout_width="150px"
android:textSize="15px"/>
<TextView
android:id="@+id/name"
android:layout_height="wrap_content"
android:layout_width="100px"
android:textSize="15px"/>
<TextView
android:id="@+id/time"
android:layout_width="50px"
android:layout_height="wrap_content"
android:textSize="15px"/> </TableRow> </TableLayout>
package com.example.contentprovidermedia;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import android.media.MediaPlayer;
import android.os.Bundle;
import android.provider.MediaStore;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast; public class MainActivity extends Activity { private List<Map<String,String>>list=new ArrayList<Map<String,String>>();
private SimpleAdapter simpleadapter;
private ListView listview;
private String songname;
private String songtime;
private String songwriter;
private int Alltime;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview=(ListView) findViewById(R.id.songlist);
listview.setOnItemClickListener(new OnItemClickListener() { private MediaPlayer media;
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
/*
* 这个实现方法简单的说一下...parent表示的这个整体的列表,这个列表保存在适配器中...
* view表示的是列表中被选择的子选项...position表示被点击的定位...id表示的是被点击的行数...
* 这里表示的是当列表的某一行没触发时需要进行的操作...我定义的操作是,当点击到列表的某一行的时候
* 这个音乐将进行播放操作...
* */
// TODO Auto-generated method stub
Map<String,String>map=(Map<String, String>) MainActivity.this.simpleadapter.getItem(position);
String songtitle=map.get("title");
String songname=map.get("name");
String songtime=map.get("time");
String songpath=map.get("path");
palysong(songpath);
}
private void palysong(String songpath) {
// TODO Auto-generated method stub
this.media=new MediaPlayer();
media.reset();
try {
media.setDataSource(songpath);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
media.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
media.start();
}
}); ContentResolver resolver=this.getContentResolver();
/* resolver.query(uri, projection, selection, selectionArgs, sortOrder)
* uri参数:表示的是对哪个数据表进行操作..
* projection参数:表示在表中需要选取的列值..
* selection参数:表示的是查询的条件...相当于where子句..
* selectionArgs参数:表示语句中是否有?...
* sortorder参数:表示查询的结果按照什么形式进行排列...
* 查询的结果返回给Cursor对象...按行进行排列数据...
* */
Cursor cursor=resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
if(cursor==null){
Toast.makeText(MainActivity.this, "没有找到相应的数据", Toast.LENGTH_SHORT).show();
}else{
for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToLast()){
songname=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));//获取音乐的名字信息..
songwriter=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));//获取音乐的作者...
Alltime=cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));//获取音乐的时长...以毫秒为单位...
songtime=settime(Alltime);
Map<String,String>map=new HashMap<String, String>();//用一个Map来保存数据...
map.put("title", songname);
map.put("songwriter", songwriter);
map.put("maptime", songtime);
list.add(map);//将map存入到List中...
/*
* 这里使用了一个简单的适配器...
* new SimpleAdapter(context,data,resource,from,to);这是适配器的构造方法...
* context  SimpleAdapter关联的View的运行环境
* data    一个Map组成的List。在列表中的每个条目对应列表中的一行,每一个map中应该包含所有在from参数中指定的键
* resource 一个定义列表项的布局文件的资源ID。布局文件将至少应包含那些在to中定义了的ID
* from 一个将被添加到Map映射上的键名
* to     将绑定数据的视图的ID,跟from参数对应,这些应该全是TextView
*
* */
this.simpleadapter=new SimpleAdapter(this,list, R.layout.songlist, new String[]{"title","name","time"},new int[]{R.id.title,R.id.name,R.id.time});
listview.setAdapter(simpleadapter);//设置适配器...
}
}
} private String settime(int time){
time/=1000;
int minute=time/60;
int second=time%60;
minute %=60;
return String.format("%02d:%02d", minute,second); }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} }

  ContentProvider的东西很多,也很杂,其重要的作用还是实现数据的共享,掌握了如何使用这个类来完成数据共享,那么目的就达到了...主要还是掌握如何去实现应用之间去调用共享的数据...