ContentProvider
➢ContentProvider为App存取内部数据提供统- -的外部接口,让不同的应用之间得以共享
数据。
A应用
ContentProvider是Android中的一个组件,用于在应用程序之间共享数据。它提供了一种标准化的方式来访问和操作应用程序的数据,可以实现数据的增删改查、数据权限管理和数据共享等功能。
使用ContentProvider需要以下几个步骤:
-
创建ContentProvider类:创建一个继承自ContentProvider的类,用于定义数据的增删改查操作。需要实现以下几个方法:
- onCreate():在ContentProvider创建时调用,用于进行初始化操作。
- query():用于查询数据。
- insert():用于插入数据。
- update():用于更新数据。
- delete():用于删除数据。
- getType():用于返回数据的MIME类型。
public class MyContentProvider extends ContentProvider { // ... @Override public boolean onCreate() { // 初始化操作 return true; } @Nullable @Override public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { // 查询数据 // 返回Cursor对象 return cursor; } @Nullable @Override public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { // 插入数据 // 返回新插入数据的Uri return newUri; } @Override public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { // 更新数据 // 返回受影响的行数 return count; } @Override public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { // 删除数据 // 返回受影响的行数 return count; } @Nullable @Override public String getType(@NonNull Uri uri) { // 返回数据的MIME类型 return mimeType; } }
-
注册ContentProvider:在AndroidManifest.xml文件中注册ContentProvider,将其与一个唯一的authority关联起来。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <application> <!-- ... --> <provider android:name=".MyContentProvider" android:authorities="com.example.myapp.provider" android:exported="false" /> </application> </manifest>
这里的
com.example.myapp.provider
是ContentProvider的authority,用于唯一标识该ContentProvider。 -
访问ContentProvider:通过ContentResolver类来访问ContentProvider。ContentResolver提供了一系列方法,用于进行数据的增删改查操作。
- query():查询数据。
- insert():插入数据。
- update():更新数据。
- delete():删除数据。
Uri uri = Uri.parse("content://com.example.myapp.provider/users"); // 查询数据 Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); // 插入数据 Uri newUri = getContentResolver().insert(uri, values); // 更新数据 int count = getContentResolver().update(uri, values, selection, selectionArgs); // 删除数据 int count = getContentResolver().delete(uri, selection, selectionArgs);
这里的
content://com.example.myapp.provider/users
是ContentProvider的URI,用于指定要访问的数据。
以上就是使用ContentProvider的基本步骤。通过创建ContentProvider类、注册ContentProvider和使用ContentResolver来访问ContentProvider,可以实现数据的增删改查操作。同时,ContentProvider还提供了一些高级特性,如数据权限管理和数据共享等,可以根据实际需求进行使用。
总结:
ContentProvider是Android中的一个组件,用于在应用程序之间共享数据。使用ContentProvider需要创建ContentProvider类、注册ContentProvider和使用ContentResolver来访问ContentProvider。通过实现ContentProvider类的方法,可以实现数据的增删改查操作。同时,ContentProvider还提供了一些高级特性,如数据权限管理和数据共享等,可以根据实际需求进行使用。
运行时动态申请权限
➢Android系统为了防止某些App滥用权限,从6.0开始引入 了运行时权限管理机制,允许A
pp在运行过程中动态检查是否拥有某项权限,- -旦发现缺少某种必需的权限,则系统会
自动弹出小窗提示用户去开启该权限。
在Android中,有一些敏感权限需要在运行时动态申请,例如访问相机、读取联系人、获取位置等。以下是一些关于在运行时动态申请权限的笔记:
- 在AndroidManifest.xml文件中声明所需的权限。例如,如果您的应用需要访问相机,您需要在清单文件中添加以下权限声明:
<uses-permission android:name="android.permission.CAMERA" />
- 检查应用是否已被授予所需的权限。您可以使用
ContextCompat.checkSelfPermission()
方法来检查应用是否已被授予特定的权限。例如,检查相机权限是否已被授予:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
// 相机权限已被授予
} else {
// 相机权限未被授予,需要动态申请权限
}
- 动态申请权限。如果权限未被授予,您需要使用
ActivityCompat.requestPermissions()
方法来请求权限。此方法将显示一个系统对话框,向用户解释为什么需要该权限,并询问用户是否授予权限。例如,请求相机权限:
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
- 处理权限请求结果。当用户响应权限请求时,系统将调用
onRequestPermissionsResult()
方法,并传递权限请求结果。您需要在此方法中处理权限请求结果。例如,检查相机权限请求的结果:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户授予了相机权限
} else {
// 用户拒绝了相机权限
}
}
}
- 处理权限被拒绝的情况。如果用户拒绝了权限请求,您可以向用户解释为什么需要该权限,并提供一个适当的操作,例如打开应用设置页面让用户手动授予权限。例如,打开应用设置页面:
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, APP_SETTINGS_REQUEST_CODE);
- 在
onActivityResult()
方法中处理从应用设置页面返回的结果。当用户在应用设置页面授予或拒绝权限时,系统将调用onActivityResult()
方法,并传递结果。您可以在此方法中处理用户的操作结果。
这些是在运行时动态申请权限的基本步骤。请注意,不同的权限可能需要不同的处理方式,具体取决于您的应用需求。您可以根据需要进行适当的调整和扩展。
动态申请权限的步骤
➢检查App是否开启了指定权限
●调用ContextCompat的checkSelfPermission方法。
➢请求系统弹窗,以便用户选择是否开启权限
●调用ActivityCompat的requestPermissions方法, 即可命令系统自动弹出权限申请窗口。
➢判断用户的权限选择结果
●重写活动页面的权限请求回调方法onRequestPermissionsResult,在该方法内部处理用户的权限选择结果。
运行时动态申请权限Lazy模式
运行时动态申请权限Lazy模式是一种简化动态申请权限流程的方式,它可以让您在不需要处理权限请求结果的情况下,直接使用需要的权限。
实现Lazy模式的基本步骤如下:
- 在您的Activity中,定义一个
PermissionRequester
类。这个类将负责处理权限请求和权限请求结果。例如:
public class MainActivity extends AppCompatActivity {
private PermissionRequester mPermissionRequester;
// ...
private void initPermission() {
mPermissionRequester = new PermissionRequester(this);
mPermissionRequester.request(Manifest.permission.CAMERA);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
mPermissionRequester.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
// ...
}
- 在
PermissionRequester
类中,定义一个request()
方法,用于请求权限。在这个方法中,检查应用是否已被授予所需的权限。如果已被授予,直接调用回调方法通知调用者。如果未被授予,动态申请权限。例如:
public class PermissionRequester {
private Activity mActivity;
public PermissionRequester(Activity activity) {
mActivity = activity;
}
public void request(String permission, final OnPermissionGrantedListener listener) {
if (ContextCompat.checkSelfPermission(mActivity, permission) == PackageManager.PERMISSION_GRANTED) {
// 权限已被授予,直接回调通知调用者
listener.onPermissionGranted();
} else {
// 权限未被授予,动态申请权限
ActivityCompat.requestPermissions(mActivity, new String[]{permission}, new OnPermissionRequestResultListener() {
@Override
public void onPermissionRequestResult(boolean granted) {
if (granted) {
// 权限已被授予,回调通知调用者
listener.onPermissionGranted();
} else {
// 权限未被授予,回调通知调用者
listener.onPermissionDenied();
}
}
});
}
}
public interface OnPermissionGrantedListener {
void onPermissionGranted();
void onPermissionDenied();
}
}
- 在您的Activity中,调用
PermissionRequester
类的request()
方法来请求权限,并传递一个回调接口。例如:
private void initPermission() {
mPermissionRequester = new PermissionRequester(this);
mPermissionRequester.request(Manifest.permission.CAMERA, new PermissionRequester.OnPermissionGrantedListener() {
@Override
public void onPermissionGranted() {
// 相机权限已被授予,可以直接使用相机
}
@Override
public void onPermissionDenied() {
// 用户拒绝了相机权限,需要向用户解释为什么需要该权限,并提供一个适当的操作,例如打开应用设置页面让用户手动授予权限
}
});
}
这些是实现运行时动态申请权限Lazy模式的基本步骤。请注意,不同的权限可能需要不同的处理方式,具体取决于您的应用需求。您可以根据需要进行适当的调整和扩展。
运行时动态申请权限Hungry模式
运行时动态申请权限Hungry模式是一种在需要权限的时候立即请求权限,并在请求结果返回后处理权限请求结果的方式。
实现Hungry模式的基本步骤如下:
- 在您的Activity中,定义一个
PermissionRequester
类。这个类将负责处理权限请求和权限请求结果。例如:
public class MainActivity extends AppCompatActivity {
private PermissionRequester mPermissionRequester;
// ...
private void initPermission() {
mPermissionRequester = new PermissionRequester(this);
mPermissionRequester.request(Manifest.permission.CAMERA, new PermissionRequester.OnPermissionRequestResultListener() {
@Override
public void onPermissionRequestResult(boolean granted) {
if (granted) {
// 权限已被授予,可以直接使用相机
} else {
// 用户拒绝了相机权限,需要向用户解释为什么需要该权限,并提供一个适当的操作,例如打开应用设置页面让用户手动授予权限
}
}
});
}
// ...
}
- 在
PermissionRequester
类中,定义一个request()
方法,用于请求权限。在这个方法中,检查应用是否已被授予所需的权限。如果已被授予,直接调用回调方法通知调用者。如果未被授予,动态申请权限并在回调方法中处理权限请求结果。例如:
public class PermissionRequester {
private Activity mActivity;
public PermissionRequester(Activity activity) {
mActivity = activity;
}
public void request(String permission, final OnPermissionRequestResultListener listener) {
if (ContextCompat.checkSelfPermission(mActivity, permission) == PackageManager.PERMISSION_GRANTED) {
// 权限已被授予,直接回调通知调用者
listener.onPermissionRequestResult(true);
} else {
// 权限未被授予,动态申请权限
ActivityCompat.requestPermissions(mActivity, new String[]{permission}, new OnPermissionRequestResultListener() {
@Override
public void onPermissionRequestResult(boolean granted) {
// 回调通知调用者
listener.onPermissionRequestResult(granted);
}
});
}
}
public interface OnPermissionRequestResultListener {
void onPermissionRequestResult(boolean granted);
}
}
- 在您的Activity中,调用
PermissionRequester
类的request()
方法来请求权限,并传递一个回调接口。在回调接口的方法中处理权限请求结果。例如:
private void initPermission() {
mPermissionRequester = new PermissionRequester(this);
mPermissionRequester.request(Manifest.permission.CAMERA, new PermissionRequester.OnPermissionRequestResultListener() {
@Override
public void onPermissionRequestResult(boolean granted) {
if (granted) {
// 权限已被授予,可以直接使用相机
} else {
// 用户拒绝了相机权限,需要向用户解释为什么需要该权限,并提供一个适当的操作,例如打开应用设置页面让用户手动授予权限
}
}
});
}
这些是实现运行时动态申请权限Hungry模式的基本步骤。请注意,不同的权限可能需要不同的处理方式,具体取决于您的应用需求。您可以根据需要进行适当的调整和扩展。
利用ContentObserver监听短信
要利用ContentObserver监听短信通知,可以按照以下步骤进行操作:
- 创建一个继承自ContentObserver的类,用于监听短信通知的变化。在这个类中,重写onChange()方法来处理短信通知的变化。例如:
public class SmsContentObserver extends ContentObserver {
private Context mContext;
public SmsContentObserver(Context context) {
super(null);
mContext = context;
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// 处理短信通知的变化
}
}
- 在需要监听短信通知的地方,注册ContentObserver。例如,在Activity的onCreate()方法中注册ContentObserver:
private SmsContentObserver mSmsContentObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSmsContentObserver = new SmsContentObserver(this);
getContentResolver().registerContentObserver(Telephony.Sms.CONTENT_URI, true, mSmsContentObserver);
}
- 在不需要监听短信通知的地方,记得取消注册ContentObserver。例如,在Activity的onDestroy()方法中取消注册:
@Override
protected void onDestroy() {
super.onDestroy();
getContentResolver().unregisterContentObserver(mSmsContentObserver);
}
通过以上步骤,您可以利用ContentObserver监听短信通知的变化。在onChange()方法中,您可以处理短信通知的变化,例如提取短信内容、发送通知等。请注意,您需要获取相应的权限(如READ_SMS)才能监听短信通知。
notifyForDescendents
是ContentObserver
的一个方法,用于指定是否监听指定URI的所有子URI。当设置为true
时,如果指定的URI有任何子URI发生变化,ContentObserver
会收到通知;当设置为false
时,只有指定的URI本身发生变化时,ContentObserver
才会收到通知。
使用notifyForDescendents
方法时,需要在注册ContentObserver
时指定notifyForDescendents
参数。例如:
getContentResolver().registerContentObserver(uri, true, contentObserver);
其中,uri
是要监听的URI,true
表示监听所有子URI的变化,contentObserver
是继承自ContentObserver
的观察者对象。
如果您只想监听指定URI本身的变化,而不关心其子URI的变化,可以将notifyForDescendents
参数设置为false
:
getContentResolver().registerContentObserver(uri, false, contentObserver);
在ContentObserver
的onChange
方法中,可以根据需要处理收到的通知。例如,可以提取变化的数据、更新界面等操作。
请注意,notifyForDescendents
方法在不同的Android版本中可能会有不同的行为,请根据您的需求和目标设备选择适当的设置。
跳转相册选图片发送彩信
要实现从相册选择图片并发送彩信,您可以按照以下步骤进行操作:
- 在AndroidManifest.xml文件中添加相应的权限:
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- 在您的Activity中添加一个按钮,用于触发选择图片的操作:
<Button
android:id="@+id/choose_image_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择图片" />
- 在Activity中,为按钮添加点击事件,并在事件处理方法中打开相册:
private static final int REQUEST_CODE_PICK_IMAGE = 1;
Button chooseImageButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chooseImageButton = findViewById(R.id.choose_image_button);
chooseImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openGallery();
}
});
}
private void openGallery() {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_PICK_IMAGE && resultCode == RESULT_OK && data != null) {
Uri imageUri = data.getData();
sendMms(imageUri);
}
}
- 在Activity中添加一个发送彩信的方法,该方法将选择的图片Uri作为参数:
private void sendMms(Uri imageUri) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, imageUri);
intent.setType("image/*");
startActivity(intent);
}
请注意,上述代码中的REQUEST_CODE_PICK_IMAGE
是一个用于标识打开相册请求的常量,您可以根据需要自定义该常量的值。
通过以上步骤,您可以实现从相册选择图片并发送彩信的功能。当用户选择了图片后,会调用onActivityResult()
方法,其中可以获取到选择的图片Uri,然后调用sendMms()
方法发送彩信。请注意,您需要获取相应的权限(如SEND_SMS和READ_EXTERNAL_STORAGE)才能发送彩信和读取外部存储中的图片。
通过MediaStore查询图片
要使用MediaStore查询图片的详细信息,您可以按照以下步骤进行操作:
- 在AndroidManifest.xml文件中添加相应的权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- 在Activity中引入以下包:
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
- 在Activity的onCreate()方法中调用查询图片详细信息的方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
queryImageDetails();
}
- 在Activity中编写查询图片详细信息的方法:
private void queryImageDetails() {
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String[] projection = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DATE_ADDED
};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media._ID));
String name = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
long size = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.SIZE));
long dateAdded = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED));
Log.d(TAG, "ID: " + id);
Log.d(TAG, "Name: " + name);
Log.d(TAG, "Size: " + size);
Log.d(TAG, "Date Added: " + dateAdded);
}
cursor.close();
}
}
在上述代码中,我们使用MediaStore.Images.Media.EXTERNAL_CONTENT_URI
作为查询的URI,该URI用于查询外部存储中的图片。我们还定义了一个投影数组,包含要查询的列,例如图片的ID、显示名称、大小和添加日期。
然后,我们使用getContentResolver().query()
方法执行查询,并遍历查询结果。在循环中,我们提取每个图片的详细信息,例如ID、名称、大小和添加日期,并将其打印到日志中。
请注意,您可以根据需要调整投影数组和查询条件,以获取您所需的图片详细信息。
通过以上步骤,您可以使用MediaStore查询图片的详细信息。
借助FileProvider发送彩信
要使用FileProvider发送彩信,首先需要进行以下几个步骤:
- 在AndroidManifest.xml文件中,添加FileProvider的配置。在
<application>
标签内添加以下代码:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="your.package.name.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
将your.package.name
替换为您的应用程序的包名。
- 在res/xml文件夹中创建一个名为file_paths.xml的文件,并添加以下代码:
<paths>
<external-path name="external_files" path="."/>
</paths>
这将允许您访问应用的外部文件目录。
- 在您要发送的彩信方法中,创建一个File对象,以便发送的文件。
File file = new File(getExternalFilesDir(null), "your_file_name.extension");
将your_file_name.extension
替换为您要发送的文件的名称和扩展名。
- 使用FileProvider获取文件的Uri。
Uri fileUri = FileProvider.getUriForFile(this, "your.package.name.fileprovider", file);
将your.package.name
替换为您的应用程序的包名。
- 创建一个Intent来发送彩信。
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
intent.setType("image/*"); // 根据您要发送的文件类型进行设置
intent.setPackage("com.android.mms"); // 设置彩信应用的包名
startActivity(intent);
请注意,上面的示例代码假设您要发送的是图像文件。如果要发送其他类型的文件,请相应地更改setType()
方法的参数。
这样,您就可以使用FileProvider发送彩信了。确保您的应用程序具有适当的权限,并且彩信应用程序已安装在用户的设备上。
安卓应用安装
Environment.getExternalStoragePublicDirectory()
是一个Android方法,用于获取外部存储器上的公共目录路径。外部存储器通常是指SD卡或者其他可移动存储设备。
该方法的语法如下:
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_NAME);
其中,DIRECTORY_NAME
是一个参数,用于指定要获取的公共目录类型。常见的目录类型包括:
DIRECTORY_DOCUMENTS
:文档目录,用于存储用户文档文件。DIRECTORY_DOWNLOADS
:下载目录,用于存储下载的文件。DIRECTORY_PICTURES
:图片目录,用于存储用户拍摄的照片。DIRECTORY_DCIM
:相机目录,用于存储相机拍摄的照片和视频。
例如,要获取外部存储器上的下载目录路径,可以使用以下代码:
File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
需要注意的是,使用Environment.getExternalStoragePublicDirectory()
方法需要在AndroidManifest.xml文件中添加适当的权限声明:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
此外,从Android Q (10)开始,对外部存储器的访问权限有所变化。在Android Q及更高版本中,应用程序无法直接访问外部存储器上的公共目录,而是需要使用MediaStore
API或者Storage Access Framework
来进行访问。