एंड्रॉइड में ContactsContract के साथ सभी संपर्क पढ़ना
यह गाइड दिखाता है कि READ_CONTACTS परमिशन के साथ डिवाइस के संपर्कों को कैसे क्वेरी और प्रदर्शित किया जाए, एक आधुनिक RecyclerView + ViewModel आर्किटेक्चर का उपयोग करके।
अनुमतियां
<uses-permission android:name="android.permission.READ_CONTACTS" />
रनटाइम अनुरोध (API 23+) आवश्यक है।
आर्किटेक्चर अवलोकन
- ContactRepository - कर्सर क्वेरी को एनकैप्सुलेट करता है।
- ContactViewModel - बैकग्राउंड थ्रेड पर क्वेरी चलाता है,
LiveDataउजागर करता है।- >
- MainActivity - LiveData का अवलोकन करता है, RecyclerView को अपडेट करता है।
1. मॉडल (Contact.java)
public class Contact {
public final long id;
public final String name;
public final List phones;
public Contact(long id, String name, List phones) {
this.id = id; this.name = name; this.phones = phones;
}
}
2. रिपॉजिटरी (ContactRepository.java)
public class ContactRepository {
private final ContentResolver resolver;
public ContactRepository(Context context) {
this.resolver = context.getContentResolver();
}
// IO थ्रेड पर चलाने के लिए
public List fetchAllContacts() {
List result = new ArrayList<>();
Cursor cursor = resolver.query(
ContactsContract.Contacts.CONTENT_URI,
new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER},
null, null,
ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
if (cursor != null) {
while (cursor.moveToNext()) {
long id = cursor.getLong(0);
String name = cursor.getString(1);
int hasPhone = cursor.getInt(2);
List phones = new ArrayList<>();
if (hasPhone > 0) {
Cursor pCur = resolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER},
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
new String[]{String.valueOf(id)}, null);
if (pCur != null) {
while (pCur.moveToNext()) {
phones.add(pCur.getString(0));
}
pCur.close();
}
}
result.add(new Contact(id, name, phones));
}
cursor.close();
}
return result;
}
}
3. व्यूमॉडल (ContactViewModel.java)
public class ContactViewModel extends AndroidViewModel {
private final ContactRepository repo;
private final MutableLiveData> contactsLive = new MutableLiveData<>();
public ContactViewModel(@NonNull Application app) {
super(app);
repo = new ContactRepository(app);
loadContacts();
}
public LiveData> getContacts() { return contactsLive; }
private void loadContacts() {
new Thread(() -> {
List list = repo.fetchAllContacts();
contactsLive.postValue(list);
}).start();
}
}
4. एडॉप्टर (ContactAdapter.java)
public class ContactAdapter extends RecyclerView.Adapter{ private List data = new ArrayList<>(); public void setData(List list) { this.data = list; notifyDataSetChanged(); // या DiffUtil के लिए ListAdapter का उपयोग करें } @NonNull @Override public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_contact, parent, false); return new VH(v); } @Override public void onBindViewHolder(@NonNull VH h, int pos) { Contact c = data.get(pos); h.name.setText(c.name); h.phones.setText(TextUtils.join(", ", c.phones)); } @Override public int getItemCount() { return data.size(); } static class VH extends RecyclerView.ViewHolder { TextView name, phones; VH(View v) { super(v); name = v.findViewById(R.id.tvName); phones = v.findViewById(R.id.tvPhones); } } }
5. लेआउट
res/layout/item_contact.xml:
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView android:id="@+id/tvName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" android:textStyle="bold" />
<TextView android:id="@+id/tvPhones" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="#666" />
</LinearLayout>
res/layout/activity_main.xml:
<androidx.recyclerview.widget.RecyclerView
xmlns:android="https://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
6. गतिविधि (MainActivity.java)
public class MainActivity extends AppCompatActivity {
private ContactAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView rv = findViewById(R.id.recyclerView);
rv.setLayoutManager(new LinearLayoutManager(this));
adapter = new ContactAdapter();
rv.setAdapter(adapter);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 100);
} else {
observeContacts();
}
}
private void observeContacts() {
new ViewModelProvider(this).get(ContactViewModel.class)
.getContacts()
.observe(this, contacts -> adapter.setData(contacts));
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] perms, @NonNull int[] results) {
super.onRequestPermissionsResult(requestCode, perms, results);
if (requestCode == 100 && results.length > 0 && results[0] == PackageManager.PERMISSION_GRANTED) {
observeContacts();
} else {
Toast.makeText(this, "संपर्क परमिशन आवश्यक है", Toast.LENGTH_LONG).show();
}
}
}
प्रदर्शन युक्तियाँ
- कर्सर क्वेरी के लिए प्रोजेक्शन (कॉलम सूची) का उपयोग करें — सभी कॉलम (*) न चुनें।
- बड़े संपर्क पुस्तिकाओं के लिए,
CursorLoader(लीगेसी) या Room + Paging 3 पर विचार करें। - यदि केवल नाम चाहिए, तो
ContactsContract.Contacts.DISPLAY_NAMEके लिए एकल-कॉलम क्वेरी पर्याप्त है। ListAdapter+DiffUtilके साथ RecyclerView एनिमेशन सक्षम करें।
मूल उदाहरण की समीक्षा
मूल कोड मुख्य थ्रेड पर क्वेरी करता था, ListView + ArrayAdapter का उपयोग करता था, डुप्लिकेट परमिशन लॉजिक था, और फोन नंबर को UI से अलग सूची में संग्रहीत करता था (इंडेक्स मिसमैच जोखिम)। ऊपर दिया गया समाधान थ्रेड-सुरक्षित, जीवनचक्र-जागरूक है, और RecyclerView का उपयोग करता है।