文章目录
学习要求
ContentProvide
- ContentProvide为APP存取内部数据提供统一的外部接口,让不同的应用之间得以共享数据
ClientAPP将用户的输入内容,通过ContentProvide跨进程通信传递给ServerAPP,保存到数据库中。
ContentProvide不会直接操作数据库或者是文件,数据库会通过调用SQLiteDatabase来操作SQLite.
ContentProvide相当于一个窗口(门卫),你什么数据允许其他的应用来读取,就写在里面,提供这个接口。
案例
- 创建两个Module【 server端、client端】
server端
基于模板创建ContentProvide
- 命名为
UserinfoProvider
- 主要用于对数据进行增删改查
- 新建一个包
provider
- 将
UserinfoProvider
移动到provider
中
在项目清单文件中修改authorities
- 写完整类名,最好是复制
创建database的包并创建UserDBHelper
类
- 主要是用来获取到实例SQLiteDatabase
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class UserDBHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "user.db";//数据库名称
private static final String TABLE_NAME = "user_info";//表名称
private static final int DB_VERSION = 1;//数据库的版本号
private static UserDBHelper mHelper = null;
//提供一个子类的构造方法调用父类构造方法
private UserDBHelper(Context context) {
//第一个参数为:上下文、第二个参数为:数据库名称、第三个参数为:游标、第四个参数为:版本号
super(context, DB_NAME, null, DB_VERSION);
}
//利用单列模式获取数据库帮助器的唯一实例
public static UserDBHelper getInstance(Context context) {
if (mHelper == null) {
mHelper = new UserDBHelper(context);
}
return mHelper;
}
//onCreate用来创建数据库,执行表语句
@Override
public void onCreate(SQLiteDatabase db) {
//创建表
String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
" name VARCHAR NOT NULL," +
" age INTEGER NOT NULL," +
" height LONG NOT NULL," +
" weight FLOAT NOT NULL," +
" married INTEGER NOT NULL);";
db.execSQL(sql);
}
//更新数据库版本
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
- 实例化 dbHelper
- 增加
关于uri
Uri(通用资源标识符Universal Resource identifer),代表数据操作的地址,每一个ContentProvider都会有唯一的地址。
ContentProvider使用的Uri语法结构如下:content://authority/data_path/id
content:是通用前缀,表示该Uri用于ContentProvider定位资源。
authority:是授权者名称,用来确定具体由哪一个ContentProvider提供资源。因此一般authority都由类的小写全称组成,以保证唯一性。
data_path:是数据路径,用来确定请求的是哪个数据集。
id:是数据编号,用来请求单条数据。如果是多条这个字段忽略。
- 查询
UserinfoProvider
的全部代码
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
import net.lzt.server.database.UserDBHelper;
public class UserinfoProvider extends ContentProvider {
private UserDBHelper dbHelper;
@Override
public boolean onCreate() {
Log.d("ning", "UserinfoProvider onCreate");
dbHelper = UserDBHelper.getInstance(getContext());
return true;
}
//增加
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.d("ning", "UserinfoProvider insert");
//拿到SQLiteDatabase
SQLiteDatabase db = dbHelper.getReadableDatabase();
db.insert(UserDBHelper.TABLE_NAME, null, values);
return uri;
}
//查询
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Log.d("ning", "UserinfoProvider query");
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query(UserDBHelper.TABLE_NAME, projection, selection, selectionArgs, null, null, null);
return cursor;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Implement this to handle requests to delete one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public String getType(Uri uri) {
// TODO: Implement this to handle requests for the MIME type of the data
// at the given URI.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO: Implement this to handle requests to update one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
}
client端
基于Empty Activity模板创建ContentWriteActivity
- 布局资源文件
这里将之前的shape_edit_focus
、shape_edit_normal
、editext_selector
三个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"
android:padding="5dp"
tools:context=".ContentWriteActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="姓名"
android:textColor="@color/black"
android:textSize="17dp" />
<EditText
android:id="@+id/et_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:text="lisa"
android:inputType="text"
android:maxLength="12"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="年龄"
android:textColor="@color/black"
android:textSize="17dp" />
<EditText
android:id="@+id/et_age"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:text="19"
android:inputType="number"
android:maxLength="2"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="身高"
android:textColor="@color/black"
android:textSize="17dp" />
<EditText
android:id="@+id/et_height"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:text="162"
android:inputType="numberDecimal"
android:maxLength="3"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="体重"
android:textColor="@color/black"
android:textSize="17dp" />
<EditText
android:id="@+id/et_weight"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:text="98"
android:inputType="numberDecimal"
android:maxLength="5"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<CheckBox
android:id="@+id/ck_married"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:gravity="center"
android:text="已婚"
android:textColor="@color/black"
android:textSize="17sp" />
<Button
android:id="@+id/btn_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="保存"
android:textColor="@color/black"
android:textSize="17sp" />
<Button
android:id="@+id/btn_read"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="读取"
android:textColor="@color/black"
android:textSize="17sp" />
<Button
android:id="@+id/btn_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="删除"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
效果展示
UserinfoContent
【这里需要访问ContentProvider需要用到ContentResolve】
通过ContentResolve访问数据
利用ContentProvider只实现服务端App的数据封装,如果客户端App想访问对方的内部数据,就要通过内容解析器ContentResolver访问。
- insert
- uri
单独定义一个类UserinfoContent
UserinfoContent
的全部代码
import android.net.Uri;
import android.provider.BaseColumns;
public class UserinfoContent implements BaseColumns {
public static final String AUTHORITIES = "net.lzt.server.provider.UserinfoProvider";
//最终访问路径://content://net.lzt.server.provider.UserinfoProvider/user
//访问内容提供器的URI
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITIES + "/user");
//构建字段名:该表的各个字段
public static final String USER_NAME = "name";
public static final String USER_AGE = "age";
public static final String USER_HEIGHT = "height";
public static final String USER_WEIGHT = "weight";
public static final String USER_MARRIED = "married";
}
- 这里需要构建一个
User
对象,再讲User
对象打印出来
- 实体类
User
的完整代码
public class User {public int id; //序号
public String name; //姓名
public int age; //年龄
public int height; //身高
public float weight; //体重
public boolean married; //婚否
//无参的构造方法
public User() {
}
//有参数的构造方法
public User(String name, int age, int height, float weight, boolean married) {
this.name = name;
this.age = age;
this.height = height;
this.weight = weight;
this.married = married;
}
//后面查询
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", height=" + height +
", weight=" + weight +
", married=" + married +
'}';
}
}
ContentWriteActivity
的完整代码
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class ContentWriteActivity extends AppCompatActivity implements View.OnClickListener {
private EditText et_name;
private EditText et_age;
private EditText et_height;
private EditText et_weight;
private CheckBox ck_married;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_write);
et_name = findViewById(R.id.et_name);
et_age = findViewById(R.id.et_age);
et_height = findViewById(R.id.et_height);
et_weight = findViewById(R.id.et_weight);
ck_married = findViewById(R.id.ck_married);
//设置监听
findViewById(R.id.btn_save).setOnClickListener(this);
findViewById(R.id.btn_read).setOnClickListener(this);
findViewById(R.id.btn_delete).setOnClickListener(this);
}
@SuppressLint("Range")
@Override
public void onClick(View view) {
switch (view.getId()) {
//保存【访问 ContentProvide】//添加
case R.id.btn_save:
ContentValues values = new ContentValues();
values.put(UserinfoContent.USER_NAME, et_name.getText().toString());
values.put(UserinfoContent.USER_AGE, Integer.parseInt(et_age.getText().toString()));
values.put(UserinfoContent.USER_HEIGHT, Integer.parseInt(et_height.getText().toString()));
values.put(UserinfoContent.USER_WEIGHT, Float.parseFloat(et_weight.getText().toString()));
values.put(UserinfoContent.USER_MARRIED, ck_married.isChecked());
getContentResolver().insert(UserinfoContent.CONTENT_URI, values);
Toast.makeText(ContentWriteActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
break;
//读取
case R.id.btn_read:
Cursor cursor = getContentResolver().query(UserinfoContent.CONTENT_URI, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
User info = new User();
info.id = cursor.getInt(cursor.getColumnIndex(UserinfoContent._ID));
info.name = cursor.getString(cursor.getColumnIndex(UserinfoContent.USER_NAME));
info.age = cursor.getInt(cursor.getColumnIndex(UserinfoContent.USER_AGE));
info.height = cursor.getInt(cursor.getColumnIndex(UserinfoContent.USER_HEIGHT));
info.weight = cursor.getFloat(cursor.getColumnIndex(UserinfoContent.USER_WEIGHT));
info.married = cursor.getInt(cursor.getColumnIndex(UserinfoContent.USER_MARRIED)) == 1 ? true : false;
Log.d("ning", info.toString());
}
cursor.close();
}
break;
}
}
}extends AppCompatActivity implements View.OnClickListener {
private EditText et_name;
private EditText et_age;
private EditText et_height;
private EditText et_weight;
private CheckBox ck_married;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_write);
et_name = findViewById(R.id.et_name);
et_age = findViewById(R.id.et_age);
et_height = findViewById(R.id.et_height);
et_weight = findViewById(R.id.et_weight);
ck_married = findViewById(R.id.ck_married);
//设置监听
findViewById(R.id.btn_save).setOnClickListener(this);
findViewById(R.id.btn_read).setOnClickListener(this);
findViewById(R.id.btn_delete).setOnClickListener(this);
}
@SuppressLint("Range")
@Override
public void onClick(View view) {
switch (view.getId()) {
//保存【访问 ContentProvide】//添加
case R.id.btn_save:
ContentValues values = new ContentValues();
values.put(UserinfoContent.USER_NAME, et_name.getText().toString());
values.put(UserinfoContent.USER_AGE, Integer.parseInt(et_age.getText().toString()));
values.put(UserinfoContent.USER_HEIGHT, Integer.parseInt(et_height.getText().toString()));
values.put(UserinfoContent.USER_WEIGHT, Float.parseFloat(et_weight.getText().toString()));
values.put(UserinfoContent.USER_MARRIED, ck_married.isChecked());
getContentResolver().insert(UserinfoContent.CONTENT_URI, values);
Toast.makeText(ContentWriteActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
break;
//读取
case R.id.btn_read:
Cursor cursor = getContentResolver().query(UserinfoContent.CONTENT_URI, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
User info = new User();
info.id = cursor.getInt(cursor.getColumnIndex(UserinfoContent._ID));
info.name = cursor.getString(cursor.getColumnIndex(UserinfoContent.USER_NAME));
info.age = cursor.getInt(cursor.getColumnIndex(UserinfoContent.USER_AGE));
info.height = cursor.getInt(cursor.getColumnIndex(UserinfoContent.USER_HEIGHT));
info.weight = cursor.getFloat(cursor.getColumnIndex(UserinfoContent.USER_WEIGHT));
info.married = cursor.getInt(cursor.getColumnIndex(UserinfoContent.USER_MARRIED)) == 1 ? true : false;
Log.d("ning", info.toString());
}
cursor.close();
}
break;
}
}
}
修改AndroidManifest
运行效果
【先运行server,然后运行client】
由运行结果可知在应用启动时就创建了UserinfoProvider
删除
- 构建匹配器
- 最终运行效果
已经实现了增删改查的相关内容