Content Provider 介绍

Content Provider属于Android应用程序的组件之一,作为应用程序的组件之一,作为应用程序之间唯一的共享数据的途径,Content Provider为存储和读取数据提供了统一的接口。Content Provider主要的功能就是存储并检索数据以及向其他应用程序提供访问数据的接口。Android系统为一些常见的数据类型(如音乐、视频、图像、手机通讯录联系人信息等)内置了一系列的Content Provider,这些都位于android.provider包下。持有特定的许可,可以在自己开发的应用程序中,可以在自己开发的应用程序中访问这些Content Provider,应用程序可以实现数据共享让自己的数据和其他应用程序共享

让自己的数据和其他应用程序共享有两种方式:

创建自己的Content Provider(即继承ContentProvider子类)将自己的数据添加到已有的Content Provider中去

后者需要保证现有的Content Provider和自己的数据类型相同且具有该Content Provider的写入权限

数据模型

Content Provider将其存储的数据以数据表形式提供给访问者,在数据表中,每一行为一条记录,每一列为具有特定类型和意义的数据。每一条数据记录都包括一个”ID“数值字段,该字段标识一条数据

访问Content Provider中的数据:

访问Content Provider中的数据主要ContentResolver对象,ContentResolver可以用来对Content Provider中的数据进行查询query()、插入insert()、修改update()和删除delete()等操作,以查询为例,查询一个Content Provider需要掌握如下的信息:

唯一标识Content Provider的URI需要访问的数据字段名称该数据字段的数据类型

查询Content Provider的方法有两个:ContentResolver的query()和Activity对象的managedQuery()

提供的函数

query()查询,insert()插入,update()更新,delete()删除,getType()得到数据 类型,onCreate()创建时的回调函数

实现过程

定义一个CONTENT_URI常量

定义一个类,继承Content Provider

实现query(),delete(),update(),insert(),onCreate(),getType()方法

在自己创建的模块的AndroidManifest.xml中创建权限

<permission android:name="myDB.permossion" android:protectionLevel="normal"></permission>

在AndroidManifest中申请权限

<uses-permission android:name="myDb.permisson"></uses-permission>

db AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="myDb.permisson"></uses-permission>

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SubActivity02">
</activity>
<activity android:name=".SubActivity03">
</activity>
<service android:name=".service.MyService01">

</service>
<service android:name=".service.MyBindService">

</service>
<receiver android:name=".MyReceiver.MyReceiver"
android:exported="false">
<intent-filter android:priority="10">
<action android:name="guolvRuleaaa">
</action>
</intent-filter>
</receiver>
<receiver android:name=".MyReceiver.OrderReceiver01"
android:exported="false">
<intent-filter android:priority="1000">
<action android:name="guolvRuleaaa">

</action>
</intent-filter>

</receiver>
<receiver android:name=".MyReceiver.OrderReceiver02"
android:exported="false">
<intent-filter android:priority="500">
<action android:name="guolvRuleaaa">

</action>
</intent-filter>
</receiver>
<receiver android:name=".MyReceiver.OrderReceiver03"
android:exported="false">
<intent-filter android:priority="200">
<action android:name="guolvRuleaaa">

</action>
</intent-filter>
</receiver>
</application>
</manifest>

DBHelper.java

package a.b.c.db2;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.Nullable;

public class DBHelper extends SQLiteOpenHelper
{
private static final String DBNAME = "myDbName.db";
private static final int VERSION = 1;
public static final String TABLE_USER = "user";

public DBHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version)
{
super(context, DBNAME, factory, VERSION);
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase)
{
String sqlStr = "CREATE TABLE IF NOT EXISTS " + TABLE_USER+//EXISTS后面一定要加空格
"(uid INTERGER PRIMARY KEY AUTOINCREMENT,"+
"name VARCHAR(30),"+
"age INTERGER,"+
"score DOUBLE)";
sqLiteDatabase.execSQL(sqlStr);

}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1)
{

}
}

MyProvider.java

package a.b.c.db2;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class MyProvider extends ContentProvider//MyProvider 类继承自 ContentProvider,这意味着它是一个自定义内容提供器,必须实现一些方法来处理数据的访问请求
{

private static final UriMatcher uriMacher;//UriMatcher 类型的静态变量,用于匹配 Uri。
private static final String AUTHRITY_PROVIDER = "a.b.c.db2.authority";//定义了内容提供器的授权信息,通常是包名加上 ".authority"。
private static final int CODE_PROVIDER_USER = 11;//CODE_PROVIDER_USER: 定义了一个常量,用于标识用户表格的 Uri 匹配码。
private DBHelper dbHelper;
private SQLiteDatabase db;
static
{
uriMacher = new UriMatcher(UriMatcher.NO_MATCH);//UriMatcher.NO_MATCH 表示没有匹配时的返回值。
uriMacher.addURI(AUTHRITY_PROVIDER,DBHelper.TABLE_USER,CODE_PROVIDER_USER);//addURI(AUTHRITY_PROVIDER, DBHelper.TABLE_USER, CODE_PROVIDER_USER) 将指定的授权和路径模式与匹配码关联起来。在这里,AUTHRITY_PROVIDER 是授权信息,DBHelper.TABLE_USER 是表格名,CODE_PROVIDER_USER 是匹配码。
}
@Override
public boolean onCreate()
{
dbHelper = new DBHelper(getContext(),"",null,1);
db = dbHelper.getWritableDatabase();
db.execSQL("insert into "+DBHelper.TABLE_USER+" values(1,'张三',19,87)" );
db.execSQL("insert into "+DBHelper.TABLE_USER+" values(2,'李四',18,87)" );
return true;//onCreate 方法在内容提供器创建时调用。当前实现直接返回 false,表示内容提供器的初始化失败。通常应该在这里进行初始化操作,并返回相应的结果。
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1)
{
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri)
{
return "";
}


public String getTableName(Uri uri)
{
String tableName = "";
if(uriMacher.match(uri)==CODE_PROVIDER_USER)
{
tableName = DBHelper.TABLE_USER;
}
return tableName;
}

@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues)
{
String tableName = getTableName(uri);
if(TextUtils.isEmpty(tableName))
{
return null;
}
long insertCount = db.insert(tableName,null,contentValues);
if(insertCount>0)
{
Log.i("MyProvider","insert ok");
}
else
{
Log.i("MyProvier","insert fail");
}
return uri;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings)
{
String tableName = getTableName(uri);
if(TextUtils.isEmpty(tableName))
{
return 0;
}
int deleteCount = db.delete(tableName,s,strings);
if(deleteCount>0)
{
Log.i("MyProvider","delete ok");
}
else
{
Log.i("MyProvider","delete fail");
}
return deleteCount;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings)
{
String tableName = getTableName(uri);
if(TextUtils.isEmpty(tableName))
{
return 0;
}
int updateCount = db.update(tableName,contentValues,s,strings);
if(updateCount > 0)
{
Log.i("MyProvider","update ok");
}
else
{
Log.i("MyProvider","updata fail");
}
return updateCount;
}
}

四大组件汇总代码

MainActivity.java

package a.b.c.myapplication;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import a.b.c.myapplication.MyReceiver.MyReceiver;
import a.b.c.myapplication.MyReceiver.OrderReceiver01;
import a.b.c.myapplication.MyReceiver.OrderReceiver02;
import a.b.c.myapplication.MyReceiver.OrderReceiver03;
import a.b.c.myapplication.service.MyBindService;
import a.b.c.myapplication.service.MyService01;
public class MainActivity extends AppCompatActivity
{
Button btn_start,btn_startForResult;
Button btn_startService,btn_stopService;
Button btn_binService,btn_unBindService;
Button btn_sendBroadcast,btn_orderBroadcast;
MyBindService.MyBinder myBinder;
String logtag="qqqqqq";
Button btn_add,btn_del,btn_update,btn_search;
int uid = 40;
static final Uri uri = Uri.parse("content://a.b.c.db.authority/user");//Uri.parse() 是 Uri 类的静态方法,用于将字符串表示的 URI 解析为 Uri 对象
//老方法,通过复写onActivityResult函数来接受返回结构
// @Override
// protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
// {
// super.onActivityResult(requestCode, resultCode, data);
//
// if(data == null)
// {
// return;
// }
// if(resultCode == requestCode && requestCode == 234)
// {
// String ret = data.getStringExtra("key1");
// Log.i("This is ret",ret);
// }
// }
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
btn_start = findViewById(R.id.btn_startActivity);
btn_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent(MainActivity.this, SubActivity02.class);//第一个参数:谁下发的命令,第二个参数:打开哪个Activity
startActivity(intent);
}
});
// 新方法接受返回结果
ActivityResultLauncher launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result)
{
Log.i(logtag,result.getData().getStringExtra("key1"));
}
});
btn_startForResult = findViewById(R.id.btn_startActivityGetResult);
btn_startForResult.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent(MainActivity.this,SubActivity03.class);
// startActivityForResult(intent,234);
launcher.launch(intent);
}
});
btn_startService = findViewById(R.id.btn_startService);
btn_startService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent(MainActivity.this, MyService01.class);
startService(intent);
}
});
btn_stopService = findViewById(R.id.btn_stopService);
btn_stopService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent(MainActivity.this, MyService01.class);
stopService(intent);
}
});
ServiceConnection conn = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder)
{
if(iBinder instanceof MyBindService.MyBinder)
{
myBinder = (MyBindService.MyBinder) iBinder;
}
}

@Override
public void onServiceDisconnected(ComponentName componentName)
{

Log.i(logtag, "onServiceDisconnected");
}
};
btn_binService = findViewById(R.id.btn_bindService);
btn_binService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent(MainActivity.this,MyBindService.class);
bindService(intent,conn, Context.BIND_AUTO_CREATE);
}
});
btn_unBindService = findViewById(R.id.btn_unbindService);
btn_unBindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent(MainActivity.this, MyBindService.class);
try
{
unbindService(conn);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
btn_sendBroadcast = findViewById(R.id.btn_broadcast);
btn_sendBroadcast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intetnt = new Intent(MainActivity.this, MyReceiver.class);
intetnt.setAction("guolvRuleaaa");
intetnt.putExtra("key2","这是无序广播内容1");
sendBroadcast(intetnt);
}
});

OrderReceiver01 orderReceiver01 = new OrderReceiver01();
OrderReceiver02 orderReceiver02 = new OrderReceiver02();
OrderReceiver03 orderReceiver03 = new OrderReceiver03();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("guolvRuleaaa");
registerReceiver(orderReceiver01, intentFilter);
registerReceiver(orderReceiver02,intentFilter);
registerReceiver(orderReceiver03,intentFilter);

btn_orderBroadcast = findViewById(R.id.btn_orderBroadcast);
btn_orderBroadcast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent();
intent.setAction("guolvRuleaaa");
String data = "这是原始数据";
Bundle extData = new Bundle();

sendOrderedBroadcast(intent,null,new MyReceiver(),null,0,data,extData);
}
});
btn_add = findViewById(R.id.btn_add);
btn_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
ContentValues values = new ContentValues();
values.put("uid",uid++);
values.put("name","王五");
values.put("age","20");
values.put("socre","78");
ContentResolver contentResolver = getContentResolver();
contentResolver.insert(uri,values);
}
});
btn_del = findViewById(R.id.btn_del);
btn_del.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
ContentResolver contentResolver = getContentResolver();
int delCount = contentResolver.delete(uri,"uid> ?",new String[]{"4"});
if(delCount > 0)
{
Log.i(logtag,"del Count: " + delCount);
}
}
});
btn_update = findViewById(R.id.btn_update);
btn_update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
ContentValues values = new ContentValues();

values.put("age","20");
ContentResolver contentResolver = getContentResolver();
int updateCount = contentResolver.update(uri,values,"uid=?",new String[]{"3"});
if(updateCount>0)
{
Log.i(logtag,"updata Count"+updateCount);
}

}
});
btn_search = findViewById(R.id.btn_search);
btn_search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
//select(字段1,字段2,字段3) from tablename where xx=xx";
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(uri,new String[]{"uid","name","age","score"},null,null,null);
if(cursor==null)
{
return ;
}
while(cursor.moveToNext())
{
@SuppressLint("Range") int uid = cursor.getInt(cursor.getColumnIndex("uid"));
@SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex("name"));
@SuppressLint("Range") int age = cursor.getInt(cursor.getColumnIndex("age"));
@SuppressLint("Range") int score= cursor.getInt(cursor.getColumnIndex("score"));
Log.i(logtag,"uid="+uid+",name="+name+",age="+age+",score="+score);



}

}
});
}
}

Activity生命周期

activity三种状态:

(1)active:当Activity运行在屏幕前台(处于当前任务活动栈的最上面),此时它获取了焦点能响应用户的操作,属于活动状态,同一个时刻只会有一个Activity处于活动(Active)。

(2)paused:当Activity失去焦点但仍对用户可见(如在它之上有另一个透明的Activity或Toast、AlertDialog等弹出弹窗时)它处于暂停状态。暂停的Activity仍然是存活状态(它保留者所有的状态和成员信息并保持窗口管理器的连接),但是在系统内存极小时可以被系统杀掉。

(3)stopped:完全被另一个Activity遮挡时处于停止状态,它仍然在内存中保留着所有的状态和成员信息。这是对用户不可见,当其他地方需要内存时它往往被系统杀掉。

Activity七个方法

(1)onCreate():在Activity创建时调用,通常做一些初始化设置,不可见,只在Activity创建时执行一次

(2)onStart():在Activity即将可见时调用,可见,在Activity中多次调用,不在前台,不可交互,初始化工作

(3)onResume:在Activity获取焦点开始与用户交互时调用,在前台,开启动画和独占设备

(4)onPause():在当前Activity被其它Activity覆盖或锁屏时调用,可见,程序状态的保持,独占设备和动画的关闭,以及一些数据的保存最好在onPause中进行,但不能太耗时

(5)onStop():在Activity对用户不可见时调用,不可见,其对象还在内存中,系统内存不足时可能不会执行onStop()方法

(6)onDestroy():在Activity销毁时调用

(7)onRestart():在Activity从停止状态再次启动时调用

android三个嵌套循环

(1)Activity完整的生命周期:从第一次调用onCreate()开始直到调用onDestroy()结束。

(2)Activity的可视生命周期:从调用onStart()到相应的调用onStop()。在这两个方法之间,可以保持显示Activity所需要的资源。如在onStart()注册一个广播接收者监听影响你的UI的改变,在onStop()中注销。

(3)Activity的前台生命周期:从调用onResume()到相应的调用onPause()。

Service的生命周期

Service的完整生命周期从调用onCreate()开始知道调用onDestroy()结束。

Service有两种使用方法:

(1)以调用Context.startService()启动,而以调用Context.stopService结束。这种情况下的Service是通过其他组件调用startService()被创建。这种service方法可以无限地运行下去,必须调用stopSelf()方法或者其他组件调用stopService()来停止它,当service被停止时,系统会销毁它

(2)以调用Context.bindService()方法建立,以调用Context.unbindService()关闭。这种情况下的Service时通过其他组件(一个客户)调用unbindService()方法来关闭这种连接。一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。

BroadcastReceive广播接收器生命周期

生命周期只有十秒左右,如果在onReceive()内做超过十秒内的事情,就会报ANR(Application No Response)程序无响应的错误信息。它的生命周期为从回调onReceive()方法开始到该方法返回结果后结束

一个activity的启动过程

每一个Activity都处于某一个状态,对于开发者来说,是无法控制其应用程序处于某一个状态的,这些均由系统来完成。

(1)第一个Activity的启动顺序:onCreate()->onStart()->onResume()

(2)当另一个Activity启动时:第一个Activity onPause()->第二个Activity onCreate()->onStart()->onResume()->第一个Activity onStop();

(3)当返回到第一个Activity时:第二个Activity onPause()->第一个Activity onRestart()->onStart()->onResume()->第二个Activity onStop()->onDestroy()