安卓四大组件

服务.

绑定和之间打开
 

俩个生命周期:普通打开服务

在创建 

在打开命令

在销毁

触发的方法有:

在创建 

在打开命令

在销毁

例子:

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();
        }
    }

}

内容提供者就是在不同应用之间共享数据的

提供了一种统一标准化接口来访问和操作数据源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值