ContentProvider提供一个接口,暴露自身的数据,其他应用就可以通过这个接口来实现源数据的增删改查。接下来我们就用一个小案例来演示一下
因为要用到Android的的四大组件之一ContentProvider,所以这里的数据提供者是menudemo
链接:https://pan.baidu.com/s/1i9mdcGIwsDch2MIh-hUTLw
提取码:0ytr
因为上传不了,所以只能给百度云的链接
下载好了之后,打开新的一个工程,File->New->Import Module,把解压好的menudemo导入
运行Menudemo,运行成功的界面的这样的
运行的过程中可能会报错,因为这个demo的环境问题跟你电脑上as的版本什么的有冲突,我是把menudemo里的build.gradle改了
把这个文件的内容改成如下:
apply plugin: 'com.android.application'
buildscript{
repositories{
jcenter()
}
dependencies{
classpath "com.android.tools.build:gradle:2.3.3"
}
}
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
applicationId "com.example.menudemo"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'com.android.support:appcompat-v7:24.2.0'
implementation 'com.android.support.constraint:constraint-layout:2.0.0-beta1'
testImplementation 'junit:junit:4.12'
}
具体的话要根据自己电脑的上AS的报错内容来改,不难的
之后就在新的工程里写代码了
这个Demo涉及到菜的名字以及类别,所以我们编写两个实体类
Dishlist.java
package com.example.myapplication.List;
public class DishList {
public final static String DISH_ID="dish_id";//数据库里面的列名
public final static String DISH_NAME="dish_name";//数据库里面的列名
public final static String DISH_TYPE="dish_type";//数据库里面的列名
private int id;
private String name;
private String type;
public DishList() { }
public DishList(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "DishList{" + "id=" + id + ", name='" + name + '\'' + ", type='" + type + '\'' + '}';
}
}
TypeList.java
package com.example.myapplication.List;
import java.util.ArrayList;
import java.util.List;
public class TypeList {
public final static String TYPE_ID = "type_id";//数据库里面的列名
public final static String TYPE_NAME = "type_name";//数据库里面的列名
private int id;
private String typename;
private List<DishList> children = new ArrayList<> ();
//无参构造
public TypeList(){}
//双参构造
public TypeList(int id, String typename) {
this.id = id;
this.typename = typename;
}
//添加子item的方法1
public void addChild(DishList dishList){
dishList.setType (getTypename ());
children.add (dishList);
}
//添加子item的方法2
public void addChild(int Childid,String Childname){
DishList child = new DishList (Childid,Childname);
child.setType (getTypename ());
children.add (child);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTypename() {
return typename;
}
public void setTypename(String typename) {
this.typename = typename;
}
public List<DishList> getChildren() {
return children;
}
public void setChildren(List<DishList> children) {
this.children = children;
}
}
然后呢就是编写一下ExpandableListView的布局
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="#436EEE">
<TextView
android:id="@+id/add_tv"
android:text="Add"
android:textSize="25dp"
android:textColor="#ffffff"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="350dp"/>
</LinearLayout>
<ExpandableListView
android:id="@+id/id_expandable_lv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ExpandableListView>
</LinearLayout>
父类的Item,也就是菜品的类型
activity_parent_item.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="56dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/id_parent_item_tv"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginLeft="40dp"
android:gravity="center_vertical"
android:text="xxx"
android:layout_gravity="center_vertical"
android:textSize="20dp"
android:textStyle="bold"/>
</LinearLayout>
子类的Item
activity_child_item.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"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<TextView
android:id="@+id/id_child_item_tv"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="20dp"
android:gravity="center_vertical"
android:textSize="16dp"
android:textStyle="bold"
tools:text="我是子item" />
</LinearLayout>
然后我们写一个Dao类,获取数据
loadDataDao
package com.example.myapplication.Dao;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import com.example.myapplication.List.DishList;
import com.example.myapplication.List.TypeList;
import java.util.ArrayList;
import java.util.List;
//从Dao这里获取数据
public class loadDataDao {
private static final String AUTHORITY = "com.imooc.menuprovider1";
private static final String TABLE_A = "type_tb";//菜品类型表
private static final String TABLE_B = "dish_tb";//菜品表
public static final Uri CONTENT_URI_A = Uri.parse("content://" + AUTHORITY + "/" + TABLE_A);
public static final Uri CONTENT_URI_B = Uri.parse("content://" + AUTHORITY + "/" + TABLE_B);
public loadDataDao(){}
//从ContentProvider中获取数据
public List<TypeList> loadDatas(ContentResolver resolver){
//将拿到的数据放回mDatas这里
List<TypeList> mDatas = new ArrayList<> ();
//查询菜品类型表
Cursor c = resolver.query (CONTENT_URI_A,null,null,null,null);
TypeList parent = null;
while (c.moveToNext ()) {
//拿到父类的Item
parent = new TypeList ();
int id = c.getInt (c.getColumnIndex (TypeList.TYPE_ID));
String Typename = c.getString (c.getColumnIndex (TypeList.TYPE_NAME));
parent.setId (id);
parent.setTypename (Typename);
mDatas.add (parent);
}
c.close ();
DishList child = null;
for (TypeList typeList : mDatas){
String pTypename = typeList.getTypename ();
Cursor c1 = resolver.query (CONTENT_URI_B,
null,
DishList.DISH_TYPE,//指定查询条件为父类的类名,
new String[]{pTypename},//指定条件值数组为typename
null);
while (c1.moveToNext ()){
child = new DishList ();
int cid = c1.getInt (c1.getColumnIndex (DishList.DISH_ID));
String cname = c1.getString (c1.getColumnIndex (DishList.DISH_NAME));
child.setId (cid);
child.setName (cname);
child.setType (pTypename);
typeList.addChild (child);
}
c1.close ();
}
return mDatas;
}
}
之后写一个适配器将数据显示到ExpandableListView上
MenuAdapter.java
package com.example.myapplication.Adapter;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.example.myapplication.List.DishList;
import com.example.myapplication.List.TypeList;
import com.example.myapplication.MainActivity;
import com.example.myapplication.R;
import java.util.List;
import static android.provider.ContactsContract.SyncState.CONTENT_URI;
public class MenuAdapter extends BaseExpandableListAdapter {
private static final String AUTHORITY = "com.imooc.menuprovider1";
private static final String TABLE_A = "type_tb";//菜品类型表
private static final String TABLE_B = "dish_tb";//菜品表
public static final Uri CONTENT_URI_A = Uri.parse ("content://" + AUTHORITY + "/" + TABLE_A);
public static final Uri CONTENT_URI_B = Uri.parse ("content://" + AUTHORITY + "/" + TABLE_B);
private Context context;
private List<TypeList> mDatas;//显示的数据集
private LayoutInflater mInflater;
private ContentResolver resolver;
public MenuAdapter(Context mContext, List<TypeList> mDatas, CallBack callBack) {
this.context = mContext;
this.mInflater = LayoutInflater.from (context);
this.mDatas = mDatas;
resolver = context.getContentResolver ();
}
public interface CallBack {
void DeleteSuccess(List<TypeList> mDatas);
}
@Override
public int getGroupCount() {
return mDatas.size ();
}
@Override
public int getChildrenCount(int groupPosition) {
return mDatas.get (groupPosition).getChildren ().size ();
}
@Override
public Object getGroup(int groupPosition) {
return mDatas.get (groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return mDatas.get (groupPosition).getChildren ().get (childPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
//数据缓存
ParentViewHolder parentViewHolder;
if (convertView == null) {
parentViewHolder = new ParentViewHolder ();
convertView = mInflater.inflate (R.layout.activity_parent_item, parent, false);
//获取到控件
parentViewHolder.p_tv = convertView.findViewById (R.id.id_parent_item_tv);
convertView.setTag (parentViewHolder);
} else {
parentViewHolder = (ParentViewHolder) convertView.getTag ();
}
parentViewHolder.p_tv.setText (mDatas.get (groupPosition).getTypename ());
return convertView;
}
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildViewHolder childViewHolder;
if (convertView == null) {
childViewHolder = new ChildViewHolder ();
convertView = mInflater.inflate (R.layout.activity_child_item, parent, false);
childViewHolder.c_tv = convertView.findViewById (R.id.id_child_item_tv);
convertView.setTag (childViewHolder);
} else {
childViewHolder = (ChildViewHolder) convertView.getTag ();
}
childViewHolder.c_tv.setText (mDatas.get (groupPosition).getChildren ().get (childPosition).getName ());
//子Item的长按事件
convertView.setOnLongClickListener (new View.OnLongClickListener () {
@Override
public boolean onLongClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder (context);
builder.setTitle ("提示!!!");
builder.setMessage ("你确定要删除嘛?");
builder.setNegativeButton ("取消", new DialogInterface.OnClickListener () {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss ();
}
});
builder.setPositiveButton ("确定", new DialogInterface.OnClickListener () {
@Override
public void onClick(DialogInterface dialog, int which) {
resolver.delete (Uri.parse ("content://com.imooc.menuprovider1"), DishList.DISH_ID, new String[]{mDatas.get (groupPosition).getChildren ().
get (childPosition).getId () + ""});
mDatas.get (groupPosition).getChildren ().remove (childPosition);
}
});
builder.create ().show ();
return true;
}
});
convertView.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
Log.e ("TAG", "子item的点击事件");
Log.e ("TAG", "子item的id是:" + mDatas.get (groupPosition).getChildren ().get (childPosition).getId ());
}
});
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
//优化性能
private static class ParentViewHolder {
TextView p_tv;
}
private static class ChildViewHolder {
TextView c_tv;
}
}
之后我们要写一个布局来增加菜品
activity_add_data.xml
<?xml version="1.0" encoding="utf-8"?>
<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=".AddDishAcitivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:text="类型" />
<Spinner
android:id="@+id/add_data_sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:text="菜名" />
<EditText
android:id="@+id/add_data_et"
android:hint="请输入菜名"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp" />
</LinearLayout>
<Button
android:id="@+id/add_data_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="确定"/>
</LinearLayout>
编写与之对应的类
AddDishActivity.java
package com.example.myapplication;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import com.example.myapplication.List.DishList;
public class AddDishActivity extends AppCompatActivity {
private static final String AUTHORITY = "com.imooc.menuprovider1";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
private Spinner spinner;
private EditText add_et;
private Button add_btn;
private ContentResolver resolver;
private String dish_type;
private String dish_name;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_data);
//默认键盘不弹出
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
initView();
onListener();
String[] arr = getResources ().getStringArray (R.array.type_name_string_arr);
ArrayAdapter<String> mSpinnerAdapter = new ArrayAdapter<String> (AddDishAcitivity.this,
android.R.layout.simple_spinner_item,arr);
spinner.setAdapter (mSpinnerAdapter);
}
private void onListener() {
spinner.setOnItemSelectedListener (new AdapterView.OnItemSelectedListener () {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String[] arr = getResources ().getStringArray (R.array.type_name_string_arr);
dish_type = arr[position];
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
add_btn.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
dish_name = add_et.getText ().toString ();
ContentValues values = new ContentValues ();
values.put(DishList.DISH_NAME, dish_name);
values.put(DishList.DISH_TYPE, dish_type);
Uri uri = resolver.insert(CONTENT_URI, values);
long id = ContentUris.parseId (uri);
Toast.makeText (AddDishAcitivity.this,"添加成功"+id,Toast.LENGTH_SHORT).show ();
startActivity (new Intent (AddDishAcitivity.this,MainActivity.class));
finish ();
}
});
}
private void initView() {
spinner = findViewById(R.id.add_data_sp);
add_et = findViewById(R.id.add_data_et);
add_btn = findViewById(R.id.add_data_btn);
resolver = getContentResolver();
}
}
别忘了要在AndroidMainfest上进行注册
还有申请对应的权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
最后就是主函数
package com.example.myapplication;
import android.Manifest;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ExpandableListView;
import android.widget.Spinner;
import android.widget.TextView;
import com.example.myapplication.Adapter.MenuAdapter;
import com.example.myapplication.Dao.loadDataDao;
import com.example.myapplication.List.TypeList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ExpandableListView ex_lv;
private MenuAdapter mAdapter;
private List<TypeList> mDatas;
private TextView addTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
int permission = ContextCompat.checkSelfPermission (this, Manifest.permission.READ_CONTACTS);
if(permission != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions (this,new String[]{
Manifest.permission.READ_CONTACTS},1);
}
int permission1 = ContextCompat.checkSelfPermission (this, Manifest.permission.WRITE_CONTACTS);
if(permission1 != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions (this,new String[]{
Manifest.permission.WRITE_CONTACTS},2);
}
ex_lv = findViewById (R.id.id_expandable_lv);
addTv = findViewById (R.id.add_tv);
addTv.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
Intent intent = new Intent (MainActivity.this,AddDishAcitivity.class);
startActivity (intent);
}
});
//1.拿到ContentProvider数据
ContentResolver contentResolver = getContentResolver ();
mDatas = new loadDataDao ().loadDatas (contentResolver);
//2.获取适配器对象
mAdapter = new MenuAdapter (this,mDatas,new MenuAdapter.CallBack (){
public void DeleteSuccess(List<TypeList> mDatas){
mAdapter.notifyDataSetChanged ();
}
});
//将数据显示到ExpandableListView上
ex_lv.setAdapter (mAdapter);
}
}
之后就可以运行在模拟器了
如果有小伙伴需要这个Demo的话可以留言啦