今天我准备写一个android 软件版本升级功能,从网上发现了一个downloadmanager配合ContentProdiver下载更新的例子,由于ContentProvider在开发中很少自定义,所以忘了很多,并且自己没有ContentProvider的笔记帮助回忆,所以今天做了一个学习笔记。
大家对这个组件都不陌生,它的主要功能就是进程间通信。例如A应该要获得B应用的数据,就可以用ContentProvider来进行数据共享。android系统中也有很多使用ContentProvider的地方,例如,我们要获得通讯录中的用户信息就是通过ContentProvider实现的,只不过他是系统定义好的,我们直接使用而已。
ContentProvider的理解
contentProvider既然是进程间通信,那么肯定可以有两个应用(一个也是可以的)。假如,现在有两个应用A和B,B应用想获得A应用中的数据,该如何做呢?有点像问答题
第一个问题,在android系统中有很多应用,B应用如何精确的找到A应用?
第二个问题,假如B应用通过某种方式精确定位到A应用了,B应用如何获得A应用的数据呢?
解:为什么可以找到A,因为Android系统提供了一个Uri,通过Uri口可以找到A,Uri有三部分组成:
*content://: 这个是Android的ContentProvider规定的,就像上网的http://协议一样
*xx.xx.xx : 这个ContentProvider的authority部分,android系统就是通过这个东西来找到操作那个ContentProvider,只要访问特定的ContentProvider这个部分就是固定的,和上网协议的域名部分一样,这部分可以随便定义。例如,com.de.contentprovider,网络上的域名可以是www.baidu.com,他们没有区别。
*data : 资源部分(或说数据部分相对于上网协议的资源路径),当访问者访问不同的资源,它是动态改变的。
需要指出的是,android 的uri所能表达的功能更丰富,它还可以支持如下的uri:
content://com.de.contentprovider/data/2
此时它要访问的资源是 data/2 ,data数据中id为2的记录。
其实我们可以把ContentProvider看成一个网站,ContentResolver(下面会说他的作用)看成浏览器,ContentResolver通过Uri找到特定的CnotentProvider,然后调用ContentProvider中的方法,然后返回给ContentResolver。就像浏览器访问服务器后服务器经过一些操作把数据给浏览器。
解:为什么B应用可以获得A应用中的数据,B应用要获得A应用中的数据要用到一个类,即ContentResolver,它可以找到ContentProvider,然后ContentProvider操作数据然后返回给ContentResolver。
ContentResolver c = context.getContentResolver();
ContentResolver中有什么方法可以用呢,操作数据组要就是“增删改查”,所以它对应的方法就是“增删改查”:
insert(Uir uri,ContentValues values);向uri对应的ContentProvider中插入数据
delete(Uri uri,String where,String[] selectionArgs);删除uri对应的ContentProvider中where匹配的数据。
update(...);
query(...);
从上面可以看出,ContentResolver和ContentProvider之间的关系就是委托关系,通过ContentResolver调用方法,它实际上调用的是ContentProvider中的方法,上面的4中方法ContentProvider中都一一对应,但是要用户自己实现。也可看成是远程调用,ContentResolver调用远程的ContentProvider中的方法
下面有个例子:
ContentResoler
package com.luo.downloadapk; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Toast; import com.luo.downloadapk.text.MatcherUtils; public class MainActivity extends AppCompatActivity { private ContentResolver contentResolver; private Uri uri = Uri.parse("content://com.luo.text/"); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initResolvers(); findViewById(R.id.btnCheck).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { query(); } }); } private void initResolvers(){ contentResolver = this.getContentResolver(); } private void query(){ //调用ContentResolver的query()方法 //实际上返回的是该Uri对应的ContentProvider的query()方法的返回值 Cursor cursor = contentResolver.query(uri,null,null,null,null); Toast.makeText(this,"远程ContentProvider返回的Cursor为:"+cursor,Toast.LENGTH_SHORT).show(); } }通过
Uri uri = Uri.parse("content://com.luo.text/");
找到对应的ContentProvider,下面是ContentProvider代码:
package com.luo.downloadapk.ContentProvideDemo; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.support.annotation.Nullable; /** * Created by LawnLuo on 12/29/16. */ public class Demo1ContentProvide extends ContentProvider { //第一次创建该ContentProdiver时调用 @Override public boolean onCreate() { System.out.println("---onCreate()----"); return false; } @Nullable @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; } //该方法返回值代表了该ContentProdiver所提供数据的MIME类型 @Nullable @Override public String getType(Uri uri) { return null; } //实现插入方法,该方法应该返回插入的记录的Uri @Nullable @Override public Uri insert(Uri uri, ContentValues values) { return null; } //实现的删除方法该方法应该返回被删除的记录条数 @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } //实现跟新方法,该方法应该返回被的记录条数 @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } }
需要注意的是在写完ContentProvider后要在Manifest.xml文件中注册一下,代码如下
<provider android:authorities="com.luo.text" android:name=".ContentProvideDemo.Demo1ContentProvide" android:exported="true"/><!--exported = true指定该ContentProvider可以在其他的应用中调用,反之则不能-->