服务.
绑定和之间打开
俩个生命周期:普通打开服务
在创建
在打开命令
在销毁
触发的方法有:
在创建
在打开命令
在销毁
例子:
MainAppActivity
package com.example.mainapp;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.example.mainapp.databinding.ActivityMainAppBinding;
public class MainAppActivity extends AppCompatActivity {
private ActivityMainAppBinding binding;
private MyService myService;
private boolean isBound = false;
private final ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
MyService.LocalBinder binder = (MyService.LocalBinder) service;
myService = binder.getService();
isBound = true;
Log.v("MyService", "服务连接时");
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
//异常断开才会触发这个方法
Log.v("MyService", "服务断开时");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainAppBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setupListeners();
}
private void setupListeners() {
binding.buttonOne.setOnClickListener(v -> {
Intent intent = new Intent(MainAppActivity.this, MyService.class);
startService(intent); // 启动服务
Log.d("MainAppActivity", "Start service button clicked");
});
binding.buttonTwo.setOnClickListener(v -> {
Intent stopIntent = new Intent(MainAppActivity.this, MyService.class);
stopService(stopIntent); // 停止服务
Log.d("MainAppActivity", "Stop service button clicked");
});
binding.bingButtonOne.setOnClickListener(v -> {
if (!isBound) {
Intent intent = new Intent(MainAppActivity.this, MyService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE); // 绑定服务
Log.d("MainAppActivity", "Bind service button clicked");
} else {
Log.d("MainAppActivity", "Service already bound");
}
});
binding.unbingButtonTwo.setOnClickListener(v -> {
if (isBound) {
unbindService(connection); // 解绑服务
isBound = false;
Log.d("MainAppActivity", "Unbind service button clicked");
} else {
Log.d("MainAppActivity", "Service not bound");
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isBound) {
unbindService(connection);
isBound = false;
}
}
}
MyService
package com.example.mainapp;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "MyService";
private volatile boolean running = true;
private int counter = 0;
public class LocalBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
private final IBinder binder = new LocalBinder();
@Override
public void onCreate() {
Log.i(TAG, "在创建");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "在打开命令");
return START_STICKY;
}
@Override
public void unbindService(ServiceConnection conn) {
Log.i(TAG, "在解绑");
super.unbindService(conn);
}
@Override
public void onDestroy() {
super.onDestroy();
running = false;
Log.i(TAG, "在销毁");
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "在绑定");
return binder;
}
}
最后在清单文件里面添加服务
<service android:name=".MyService" />
输出示例:
俩个生命周期:绑定打开服务
在创建
在绑定
在解绑
在销毁
解绑不会触发。不要重写解绑
触发的方法有
在创建
在绑定
服务连接时在ServiceConnection类中
在销毁
设置布尔值isBound来判断服务有没有绑定,绑定就true.未绑定就false
广播接收器
Android之 BroadcastReceiver广播接收器详解_android广播接收器-优快云博客
分为有序广播和无序广播,有序广播一个一个传,可以拦截(优先级高的可以拦截掉不发送给优先级低的)。无需广播传播没有顺序,传播的很快。
先注册一个广播接收器
静态注册广播接收器
1,创建一个广播接收器
package com.example.broadcastreceiverapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String msg=intent.getStringExtra("msg");
Log.e(TAG, "onReceive: "+msg);
}
}
2,在清单文件里面注册该广播接收器
<receiver
android:name=".MyReceiver"
android:exported="true" />
3,在MainActivity里面点击按钮发送广播
然后编写activity代码,页面是一个button
3.1 注意:
android 8.0以后版本对静态注册的广播做了限制,自定义的接收器会接收不到发送方发送的广播。发送方需要在intent中设定接收方的package,接收方才会接收到。如下:
Intent intent = new Intent();
intent.setAction("cn.dinghe.test");
intent.setClass(this,Class.forName("cn.dinghe.test.MyReceiver"));
sendBroadcast(intent);
package com.example.broadcastreceiverapplication;
public class MainActivity2 extends AppCompatActivity {
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main2);
Button button;
button=findViewById(R.id.activity2_sent_btn);
Intent intent = new Intent();
intent.putExtra("msg","你好");
try {
intent.setClass(this,Class.forName("com.example.broadcastreceiverapplication.MyReceiver"));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendBroadcast(intent);
}
});
}
}
动态注册广播接收器
1,先创建一个广播接收器
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "MyReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String msg=intent.getStringExtra("msg");
Log.e(TAG, "onReceive: "+msg);
}
}
2,动态注册广播接收器
MyReceiver myReceiver;
//动态注册广播
myReceiver=new MyReceiver();
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("com.example.broadcastreceiverapplication");
//RECEIVER_EXPORTED这个属性是用来选择表示该接受器是否接收来自外部应用的广播,这个代表是。
registerReceiver(myReceiver,intentFilter,RECEIVER_EXPORTED);
3,发送广播
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent();
intent.setAction("com.example.broadcastreceiverapplication");
intent.putExtra("msg","你好啊");
sendBroadcast(intent);
}
});
4,取消注册,不然容易造成内存泄漏
@Override
protected void onDestroy() {
super.onDestroy();
if (myReceiver!=null){
unregisterReceiver(myReceiver);
}
}
有序广播
Android中的有序广播与无序广播_android 有序广播-优快云博客
拦截有序广播,abortBroadcast()
创建三个广播
public class MyReceiverOne extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.e("MyReceiver", "自定义广播接收者One,已接受到了广播事件" + msg);
}
}
public class MyReceiverTwo extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg=intent.getStringExtra("msg");
Log.e("MyReceiver","自定义广播接收者Two,已接受到了广播事件"+msg);
}
}
public class MyReceiverThree extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg=intent.getStringExtra("msg");
Log.e("MyReceiver","自定义广播接收者Three,已接受到了广播事件"+msg);
}
}
在清单文件里面注册这些广播接收器
<receiver
android:name=".MyReceiverThree"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="300">
<action android:name="guagboOrder"></action>
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiverTwo"
android:enabled="true"
android:exported="true" >
<intent-filter android:priority="200">
<action android:name="guagboOrder"></action>
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiverOne"
android:enabled="true"
android:exported="true" >
<intent-filter android:priority="100">
<action android:name="guagboOrder"></action>
</intent-filter>
</receiver>
在activity里面发送有序广播
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("guagboOrder");
intent.putExtra("msg", "你好啊");
intent.setPackage(getPackageName());
sendBroadcast(intent);
}
});
输出示例
无序广播
在有序的基础上修改
1,修改清单文件上的顺序,删掉。
<receiver
android:name=".MyReceiverThree"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="guagboOrder"></action>
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiverOne"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="guagboOrder"></action>
</intent-filter>
</receiver>
<receiver
android:name=".MyReceiverTwo"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="guagboOrder"></action>
</intent-filter>
</receiver>
2,在activity里面将有序调用方法换成sendBroadcast()方法
Intent intent = new Intent();
intent.setAction("guagboOrder");
intent.putExtra("msg", "你好");
intent.setPackage(getPackageName());
sendBroadcast(intent, null);
广播接收器
注册方式有
动态注册
静态注册 需要添加接收方的包名,接收方才能接收到
广播方式
有序广播 可以设置优先级(priority)来设置广播接收者接收的顺序。
无序广播 只需把有序广播上的优先级删掉,把发送有序广播改成发送广播即可
内容提供者
cursor它用于表示从数据库查询返回的结果集 cursor一开始指向表的前面,使用cursor时要先cursor.moveToNext()
使用该方法获取当前行指定哪儿列的数据
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
使用该方法循环遍历将每一行的联系人姓名和电话放到List中
while (cursor.moveToNext()) {
@SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
@SuppressLint("Range") String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneInfos.add(new PhoneInfo(name, number));
}
使用内容解析器类查询手机通讯录功能
1、创建一个手机联系人实体类
PhoneInfo
package com.example.broadcastreceiverapplication.ProviderPractice;
public class PhoneInfo {
private String name;
private String numberPhone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumberPhone() {
return numberPhone;
}
public void setNumberPhone(String numberPhone) {
this.numberPhone = numberPhone;
}
public PhoneInfo() {
}
public PhoneInfo(String name, String numberPhone) {
this.name = name;
this.numberPhone = numberPhone;
}
}
2、创建一个RecyclerViewAdapter用于对item操作
package com.example.broadcastreceiverapplication.ProviderPractice;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.broadcastreceiverapplication.R;
import java.util.ArrayList;
/**
* 数据适配已经完成
*/
public class MyPhoneUiAdapter extends RecyclerView.Adapter<MyPhoneUiViewHolder> {
//定义数据集合
ArrayList<PhoneInfo> phoneInfos;
public MyPhoneUiAdapter(ArrayList<PhoneInfo> phoneInfos) {
this.phoneInfos = phoneInfos;
}
//创建视图
@NonNull
@Override
public MyPhoneUiViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//创建视图
View view = View.inflate(parent.getContext(), R.layout.my_phone_list,null);
return new MyPhoneUiViewHolder(view);
}
//绑定数据
@Override
public void onBindViewHolder(@NonNull MyPhoneUiViewHolder holder, int position) {
//数据设置
holder.tv_name.setText(phoneInfos.get(position).getName());
//设置手机号
holder.tv_phone.setText(phoneInfos.get(position).getNumberPhone());
}
@Override
public int getItemCount() {
return phoneInfos.size();
}
}
//定义 ViewHolder
class MyPhoneUiViewHolder extends RecyclerView.ViewHolder {
TextView tv_name;
TextView tv_phone;
public MyPhoneUiViewHolder(@NonNull View itemView) {
super(itemView);
//绑定控件
tv_name = itemView.findViewById(R.id.tv_name);
tv_phone = itemView.findViewById(R.id.tv_phone);
}
}
3、my_phone_list.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="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/iv_icon"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/headimg"
android:padding="20dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="20dp"
android:padding="20dp"
android:gravity="center"
>
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#000"
android:text="name"
android:layout_marginBottom="15dp"
/>
<TextView
android:id="@+id/tv_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textColor="#000"
android:text="phone"
/>
</LinearLayout>
</LinearLayout>
4、ProviderMainMainActivity类
package com.example.broadcastreceiverapplication.ProviderPractice;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.broadcastreceiverapplication.R;
import java.util.ArrayList;
public class ProviderMainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ArrayList<PhoneInfo> phoneInfoList;
boolean readContactsPermissionGranted = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_provider_main2);
//布局初始化
initView();
}
//初始化布局
private void initView() {
recyclerView = findViewById(R.id.myRecycle);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//获取权限
getMyPermission();
}
private void getMyPermission() {
//兼容性辅助类,可以用来申请权限 PackageManager.PERMISSION_GRANTED权限已授予常量
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
//requestPermissions 这个请求码是用来识别不同权限的。
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
} else {
//设置recyclerView视图
setData();
}
}
//设置recyclerView视图
private void setData() {
phoneInfoList = getPhoneInfoDataList();
MyPhoneUiAdapter myPhoneUiAdapter = new MyPhoneUiAdapter(phoneInfoList);
recyclerView.setAdapter(myPhoneUiAdapter);
}
private ArrayList<PhoneInfo> getPhoneInfoDataList() {
ArrayList<PhoneInfo> phoneInfos = new ArrayList<>();
//使用contxt提供的内容解析器方法查询联系人信息返回对象是一个cursor
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
Log.i("Cursor", "Cursor值为:" + cursor);
if (phoneInfos != null) phoneInfos.clear();
while (cursor.moveToNext()) {
@SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
@SuppressLint("Range") String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneInfos.add(new PhoneInfo(name, number));
}
cursor.close(); // 确保cursor在使用完毕后被关闭
return phoneInfos;
}
//请求权限结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults, int deviceId) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults, deviceId);
for (int i = 0; i < permissions.length; i++) {
if ("android.permission.READ_CONTACTS".equals(permissions[i])) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
readContactsPermissionGranted = true;
}
break; // 找到READ_CONTACTS权限后退出循环
}
}
if (readContactsPermissionGranted) {
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
setData();
} else {
Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
}
}
}
给activity添加添加修改查询功能
xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ProviderPracticePhone.ProviderMainActivity"
>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#147CE4"
android:gravity="center"
android:text="我的手机通信录"
android:textColor="#EFF2F4"
android:textSize="30dp" />
<!-- 横向布局的按钮组 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="4">
<!-- 增加按钮 -->
<Button
android:id="@+id/btn_add"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="增加" />
<!-- 删除按钮 -->
<Button
android:id="@+id/btn_delete"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="删除" />
<!-- 修改按钮 -->
<Button
android:id="@+id/btn_update"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="修改" />
<!-- 查询按钮 -->
<Button
android:id="@+id/btn_query"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="查询" />
</LinearLayout>
<!--绑定控件-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/myRecycle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
activity文件
package com.example.broadcastreceiverapplication.ProviderPracticePhone;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentProviderOperation;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.broadcastreceiverapplication.R;
import java.util.ArrayList;
public class ProviderMainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ArrayList<PhoneInfo> phoneInfoList;
private static final int REQUEST_READ_CONTACTS_PERMISSION = 1;
private static final int REQUEST_WRITE_CONTACTS_PERMISSION = 2;
private boolean readContactsPermissionGranted = false;
private boolean writeContactsPermissionGranted = false;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_provider_main2);
//布局初始化
initView();
Button btn_btn=findViewById(R.id.btn_add);
Button btn_delete=findViewById(R.id.btn_delete);
Button btn_query=findViewById(R.id.btn_query);
Button btn_update=findViewById(R.id.btn_update);
btn_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addContact("小红","684864866");
}
});
btn_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
deleteContactByDisplayName("小红");
}
});
btn_update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateContact("小红","小军","111111111111");
}
});
btn_query.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
queryContacts();
}
});
}
//初始化布局
private void initView() {
recyclerView = findViewById(R.id.myRecycle);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//获取权限
getMyPermission();
}
private void getMyPermission() {
// 检查并请求 READ_CONTACTS 权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_READ_CONTACTS_PERMISSION);
} else {
readContactsPermissionGranted = true;
}
// 检查并请求 WRITE_CONTACTS 权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_CONTACTS}, REQUEST_WRITE_CONTACTS_PERMISSION);
} else {
writeContactsPermissionGranted = true;
}
// 如果两种权限都已经授予,则设置数据
if (readContactsPermissionGranted && writeContactsPermissionGranted) {
setData();
}
}
//设置recyclerView视图
private void setData() {
phoneInfoList = getPhoneInfoDataList();
MyPhoneUiAdapter myPhoneUiAdapter = new MyPhoneUiAdapter(phoneInfoList);
recyclerView.setAdapter(myPhoneUiAdapter);
}
private ArrayList<PhoneInfo> getPhoneInfoDataList() {
ArrayList<PhoneInfo> phoneInfos = new ArrayList<>();
//使用contxt提供的内容解析器方法查询联系人信息返回对象是一个cursor
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
Log.i("Cursor", "Cursor值为:" + cursor);
if (phoneInfos != null) phoneInfos.clear();
while (cursor.moveToNext()) {
@SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
@SuppressLint("Range") String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneInfos.add(new PhoneInfo(name, number));
}
cursor.close(); // 确保cursor在使用完毕后被关闭
return phoneInfos;
}
//请求权限结果
// 请求权限结果处理
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
switch (requestCode) {
case REQUEST_READ_CONTACTS_PERMISSION:
if (granted) {
readContactsPermissionGranted = true;
Toast.makeText(this, "读取联系人权限已授权", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "读取联系人权限被拒绝", Toast.LENGTH_SHORT).show();
}
break;
case REQUEST_WRITE_CONTACTS_PERMISSION:
if (granted) {
writeContactsPermissionGranted = true;
Toast.makeText(this, "写入联系人权限已授权", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "写入联系人权限被拒绝", Toast.LENGTH_SHORT).show();
}
break;
}
// 如果两种权限都已经授予,则设置数据
if (readContactsPermissionGranted && writeContactsPermissionGranted) {
setData();
}
}
private void addContact(String displayName, String phoneNumber) {
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
// Insert a raw contact
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build());
// Insert name
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName)
.build());
// Insert phone number
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Log.i("AddContact", "联系人添加成功");
} catch (Exception e) {
Log.e("AddContact", "联系人添加失败: " + e.getMessage());
}
}
private void deleteContactByDisplayName(String displayName) {
Cursor cursor = getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
new String[]{ContactsContract.Data._ID, ContactsContract.Data.RAW_CONTACT_ID},
ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME + "=?",
new String[]{ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, displayName},
null);
if (cursor != null) {
while (cursor.moveToNext()) {
@SuppressLint("Range") long rawContactId = cursor.getLong(cursor.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID));
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
int deletedRows = getContentResolver().delete(rawContactUri, null, null);
if(deletedRows > 0){
Log.i("DeleteContact", "联系人删除成功");
}
}
cursor.close();
}
}
private void updateContact(String oldDisplayName, String newDisplayName, String newPhoneNumber) {
ArrayList<PhoneInfo> phoneInfos = getPhoneInfoDataList(); // 获取当前联系人列表
for (PhoneInfo phoneInfo : phoneInfos) {
if(phoneInfo.getName().equals(oldDisplayName)){
Cursor cursor = getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
new String[]{ContactsContract.Data._ID, ContactsContract.Data.RAW_CONTACT_ID},
ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME + "=?",
new String[]{ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, oldDisplayName},
null);
if (cursor != null) {
while (cursor.moveToNext()) {
@SuppressLint("Range") long rawContactId = cursor.getLong(cursor.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID));
ContentValues values = new ContentValues();
values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, newDisplayName);
getContentResolver().update(
ContactsContract.Data.CONTENT_URI,
values,
ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
ContactsContract.Data.MIMETYPE + "=?",
new String[]{String.valueOf(rawContactId),
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE});
values.clear();
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, newPhoneNumber);
getContentResolver().update(
ContactsContract.Data.CONTENT_URI,
values,
ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
ContactsContract.Data.MIMETYPE + "=?",
new String[]{String.valueOf(rawContactId),
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE});
}
cursor.close();
}
}
}
}
private void queryContacts() {
if (readContactsPermissionGranted) {
phoneInfoList = getPhoneInfoDataList(); // 获取联系人列表
MyPhoneUiAdapter myPhoneUiAdapter = new MyPhoneUiAdapter(phoneInfoList);
recyclerView.setAdapter(myPhoneUiAdapter); // 更新RecyclerView的适配器
myPhoneUiAdapter.notifyDataSetChanged(); // 通知数据集已更改
} else {
Toast.makeText(this, "没有读取联系人的权限", Toast.LENGTH_SHORT).show();
}
}
}
内容提供者就是在不同应用之间共享数据的
提供了一种统一标准化接口来访问和操作数据源