モバイル アプリケーション開発実験 - コンテンツ プロバイダー - ContentResolver の使用

序文

  • 私は学習と参考のためにのみ、私が学んだことを先人の業績や経験と組み合わせます。
  • この記事のほとんどのソース コード コンテンツには明確なコメントが付いています。注意深く読んでください。

アドレス帳情報の読み取り

必須

  • アドレス帳インターフェイスは線形レイアウトと相対レイアウトによって構築されており、インターフェイスの効果は次の図に示されています。レイアウト ファイル contact_item.xml を作成し、インターフェイスの画像をインポートし、インターフェイス コントロールを配置し、アイテム インターフェイスの背景ファイルを作成します。ContactInfo クラスを作成し、このクラスに連絡先情報のプロパティを作成します。電話機のアドレス帳を読み取る許可を申請し、アドレス帳インターフェイスにデータを表示します。AndroidMainfest.xml ファイルにシステム アドレス帳を読み取る権限を追加します。Contacts プログラムを実行して、アドレス帳のインターフェイス効果を確認します。
    ここに画像の説明を挿入

環境

  • 最小SDK 24
  • ターゲットSDK 33
  • sourceCompatibility JavaVersion.VERSION_1_8
  • targetCompatibility JavaVersion.VERSION_1_8
  • グラドル-7.5
  • Android Studio デンキウナギ | 2022.1.1 パッチ 1
  • ナレッジ リザーブ: RecyclerView レイアウトと ContentResolver のコンテンツ学習リザーブ

実装

  • 必要なアバター画像を事前drawableにディレクトリに忘れずにインポートしてください。

メインページのレイアウト (activity_main.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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="通讯录"
        android:gravity="center"
        android:background="#4889f4"
        android:textColor="@color/white"
        android:textSize="20sp"
        />
    <androidx.recyclerview.widget.RecyclerView
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:id="@+id/list"
        android:layout_height="wrap_content"
        />

</LinearLayout>

RecyclerView ライブラリに関する質問

  • 提案: このローカル環境で、RecyclerView レイアウトが正常に使用できる場合、RecyclerView ライブラリの依存関係を導入する必要はありません。これは、他のパッケージにデフォルトで含まれているようです (プロテスト、プログラムを通常どおり実行します)。
  • インポートしたい場合は操作を参照してください。

RecyclerView ライブラリ アクションを追加

ここに画像の説明を挿入
ここに画像の説明を挿入

com.android.support:recyclerview-v7

ここに画像の説明を挿入

  • 次に、 Android ビューでモジュールのbuild.grade構成ファイルdependenciesに追加された依存関係を確認できます。

エラーを解決する

  • Android ビューで、モジュールのbuild.properties構成ファイルを追加します
android.useAndroidX=true #如果该项本来存在,则不用添加
android.enableJetifier=true

項目レイアウト(info.xml)

ここに画像の説明を挿入

<?xml version="1.0" encoding="utf-8"?>
<!--item布局文件-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:orientation="horizontal"
    >
    <ImageView
        android:id="@+id/iv"
        android:layout_width="66dp"
        android:layout_height="67dp"
        android:src="@drawable/contact_photo"
        />
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="5dp">
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:textColor="#ff8f03" />

        <TextView
            android:id="@+id/telephoneNumber"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:layout_marginTop="10dp"
            android:layout_below="@+id/name"
            android:textColor="#ff716c6d"
            android:maxLines="2"
            android:ellipsize="end"/>
    </RelativeLayout>

</LinearLayout>

アクセス権を追加する

  • AndroidMainfest.xml中央上部のタブapplicationアドレス帳へのアクセス許可を追加します
<!--添加读取系统通讯录的权限-->
<uses-permission android:name="android.permission.READ_CONTACTS" />

エンティティクラス(ContactInfo.java)を作成します。

/**
 * 实体类,用于存储联系人信息
 */
public class ContactInfo {
    
    
    private String name, telephoneNumber;

    public String getName() {
    
    
        return name;
    }

    public String getTelephoneNumber() {
    
    
        return telephoneNumber;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public void setTelephoneNumber(String telephoneNumber) {
    
    
        this.telephoneNumber = telephoneNumber;
    }
}

アダプター (MyAdapter.java) を作成します。

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

/**
 * 自定义类实现数据适配
 */
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
    
    
    private Context myContext;
    private List<ContactInfo> myContactInfos;
    public MyAdapter(Context context,List<ContactInfo> contactInfoList){
    
    
        this.myContext=context;
        this.myContactInfos=contactInfoList;
    }

    /**
     * 加载item界面的布局文件,并将RecyclerView.ViewHolder类的对象返回
     * @param parent The ViewGroup into which the new View will be added after it is bound to
     *               an adapter position.
     * @param viewType The view type of the new View.
     *
     * @return
     */
    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    
    
        View view=View.inflate(myContext,R.layout.info,null);
        MyHolder myHolder=new MyHolder(view);
        return myHolder;
    }

    /**
     * onBindViewHolder 将获取的数据设置到对应的控件上
     * @param holder The ViewHolder which should be updated to represent the contents of the
     *        item at the given position in the data set.
     * @param position The position of the item within the adapter's data set.
     */
    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
    
    
        ContactInfo contactInfo=myContactInfos.get(position);
        holder.name.setText(contactInfo.getName());
        holder.telephoneNumber.setText(contactInfo.getTelephoneNumber());
    }

    /**
     * 获取列表条目总数
     * @return
     */
    @Override
    public int getItemCount() {
    
    
        return myContactInfos.size();
    }

    /**
     * 创建MyHolder类,继承RecyclerView.ViewHolder类,在该类中获取Item界面上的控件
     */
    class MyHolder extends RecyclerView.ViewHolder{
    
    

        TextView name,telephoneNumber;
        public MyHolder(@NonNull View itemView) {
    
    
            super(itemView);
            name=itemView.findViewById(R.id.name);
            telephoneNumber=itemView.findViewById(R.id.telephoneNumber);
        }
    }
}

メインクラス (MainActivity.java) を作成します。


import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    
    
    private RecyclerView list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //申请权限
        getPermission();

        // 获取RecyclerView控件
        list=findViewById(R.id.list);
        // 设置item分割线
        list.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
        // 设置RecyclerView的显示方式为垂直布局
        list.setLayoutManager(new LinearLayoutManager(MainActivity.this,LinearLayoutManager.VERTICAL,true));
        // 通过setAdapter方法将适配器对象设置到RecyclerView控件上
        MyAdapter myAdapter=new MyAdapter(this,getContacts());
        list.setAdapter(myAdapter);

    }

    /**
     * 申请权限
     */
    public void getPermission(){
    
    
        //检查权限是否允许
        if (ActivityCompat.checkSelfPermission(this,"android.permission.READ_CONTACTS")!= PackageManager.PERMISSION_GRANTED){
    
    
            //请求android.permission.READ_CONTACTS权限
            ActivityCompat.requestPermissions(this,new String[]{
    
    "android.permission.READ_CONTACTS"},666);
            //shouldShowRequestPermissionRationale 检查是否需要展示请求权限的提示
            //首次运行程序时,选择允许权限访问,之后再次打开应用就不会出现请求权限的提示
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,"android.permission.READ_CONTACTS")){
    
    
                Toast.makeText(this, "需要开启联系人权限", Toast.LENGTH_SHORT).show();
            }else {
    
    
                ActivityCompat.requestPermissions(this,new String[]{
    
    "android.permission.READ_CONTACTS"},666);
            }
        }
    }

    /**
     * 手动请求权限之后的结果回调
     * @param requestCode 请求吗
     * @param permissions 系统的权限数据
     * @param grantResults 请求码的状态
     *
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    
    
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode==666){
    
    
            /*
                判断权限数组中是否有一个状态值为android.permission.READ_CONTACTS 该状态值表示允许读取系统短信。
                如果有该状态值,提示联系人权限申请成功,否则,失败
            * */
            for (int i=0;i<permissions.length;i++){
    
    
                if(permissions[i].equals("android.permission.READ_CONTACTS") && grantResults[i]==PackageManager.PERMISSION_GRANTED){
    
    
                    Toast.makeText(this, "联系人权限申请成功", Toast.LENGTH_SHORT).show();
                    return;
                }
            }
            Toast.makeText(this, "联系人权限申请失败", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 通过ContactInfo类和cursor遍历获取系统通讯录的联系人信息
     * @return
     */
    public List<ContactInfo> getContacts(){
    
    
        List<ContactInfo> contactInfos=new ArrayList<>();
        Cursor cursor01=getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
        while (cursor01.moveToNext()){
    
    
            ContactInfo contactInfo=new ContactInfo();
            String Name,phone,id;
            //获取name,并存入contactInfo
            Name=cursor01.getString(cursor01.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
            contactInfo.setName(Name);
            id=cursor01.getString(cursor01.getColumnIndexOrThrow(ContactsContract.Contacts._ID));

            //获取phoneNumber,并存入contactInfo
            Cursor cursor02=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+id,null,null);
            while (cursor02.moveToNext()){
    
    
                phone=cursor02.getString(cursor02.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER));
                contactInfo.setTelephoneNumber(phone);
            }
            //将其contactInfo存入contactInfos集合中
            contactInfos.add(contactInfo);
            //关闭游标
            cursor02.close();
        }
        cursor01.close();
        //最终返回list集合
        return contactInfos;
    }

}

テストを実行する

ここに画像の説明を挿入

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/yang2330648064/article/details/130666988