Table of content
- Content Provider in Android
- How Content Provider works in Android
- Implementation of Content Provider for fetching Contact List :
Content Provider in Android
- A content provider is a component of the Android, allows apps to share data with other apps or access data from other apps.
- It acts as a bridge between apps and a structured data source, such as a database or file system.
- Content providers are a fundamental part of the Android Content Provider API.
- Plays a crucial role in enabling data sharing and data access among different apps in a secure and controlled manner.
How Content Provider works in Android
- Creation of a Content Provider: Extending the ContentProvider class or implementing the necessary methods and specifying the data source.
public class MDataProvider extends ContentProvider {
// Implement the necessary methods.
}
- Content URIs: Content Provider defines content URIs that serve as unique identifiers for specific data or data sets. These content URIs are used by other apps to request data.
- Content Resolver: Apps that want to interact with a Content Provider use a component called a ContentResolver, which is responsible for sending requests to the Content Provider and managing the communication.
- Data access request: An app that wants to access data from a Content Provider creates a Uri object with the content URI of the data it wishes to access.
Uri contentUri = Uri.parse("content://com.example.myapp.provider/data");
- Permission Checks: Before the request is sent to the Content Provider, Android checks whether the requesting app has the necessary permissions to access the data. This is defined in the AndroidManifest.xml of the Content Provider’s app.
<uses-permission android:name="com.example.myapp.permission.READ_DATA" />
In the provider definition :
<provider
android:name=".MDataProvider"
android:authorities="com.example.myapp.data"
android:readPermission="com.example.myapp.permission.READ_DATA"
android:writePermission="com.example.myapp.permission.WRITE_DATA" />
- Content Resolver Usage/Implementation of CRUD Operation: The app then uses the Content Resolver to perform data access operations. These operations include:
- query: To retrieve data.
- insert: To add new data.
- update: To modify existing data.
- delete: To remove data.
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// Implement the query operation.
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// Implement the insert operation.
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// Implement the update operation.
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Implement the delete operation.
}
ContentResolver contentResolver = getContentResolver();
Uri dataUri = Uri.parse("content://com.example.myapp.data/some_data");
Cursor cursor = contentResolver.query(dataUri, null, null, null, null);
// Process the data from the cursor.
-
Data Sharing: If the Content Provider is set up for data sharing, it can expose data to other apps securely. This can be used for various purposes, such as sharing contact information, media files, or custom data.
-
Data Security and Permissions: crucial aspect of Content Providers. Users must grant these permissions for apps to access data.
-
Content Provider Configuration: Includes specifying the authority (a unique identifier), defining the MIME type for the data, and implementing the necessary methods to handle data operations.
-
Testing and Debugging: Developers can use tools like the Android Debug Bridge (ADB) and LOGCAT to test and debug the Content Provider, making sure it works as intended and adheres to security and privacy requirements.
Implementation of Content Provider for fetching Contact List :
Step 1: Add a contact data class to handle the fields cleanly
class ContactData (val name: String, val number: String)
Step 2: Add adapter for the items of contacts list
class ContactListAdapter(private val contacts: List<ContactData>) :
RecyclerView.Adapter<ContactListAdapter.ContactViewHolder>() {
private lateinit var binding: ContactBinding
override fun getItemCount() = contacts.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContactViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
binding = ContactBinding.inflate(layoutInflater, parent, false)
return ContactViewHolder(binding.root)
}
override fun onBindViewHolder(holder: ContactViewHolder, position: Int) {
holder.apply {
val contact = contacts[position]
bind(contact)
}
}
inner class ContactViewHolder(private val v: View) : RecyclerView.ViewHolder(v) {
fun bind(contact: ContactData) {
val name = v.findViewById<TextView>(R.id.name)
val number = v.findViewById<TextView>(R.id.number)
name.text = contact.name
number.text = contact.number
}
}
}
Step 3: Now implement the content provider
class ContactListActivity : AppCompatActivity() {
private lateinit var binding: ActivityContactListBinding
private lateinit var contactAdapter: ContactListAdapter
private var contacts = ArrayList<ContactData>()
private var contactsStr = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityContactListBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.apply {
fab.setOnClickListener {
syncContacts()
}
}
}
@SuppressLint("ObsoleteSdkInt")
private fun syncContacts() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& checkSelfPermission(Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED
) {
requestPermissions(
arrayOf(Manifest.permission.READ_CONTACTS),
PERMISSION_REQ_READ_CONTACTS
)
} else {
fetchContacts()
setAdapter()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQ_READ_CONTACTS) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
syncContacts()
} else {
Snackbar.make(
this,
binding.root,
"Permission Not Granted",
Snackbar.LENGTH_SHORT
)
.show()
}
}
}
@SuppressLint("Range", "Recycle")
private fun fetchContacts() {
val resolver: ContentResolver = contentResolver
val cursor = resolver.query(
ContactsContract.Contacts.CONTENT_URI,
null, null, null, null
)
if (cursor!!.count > 0) {
while (cursor.moveToNext()) {
val id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
val name =
cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
val phoneNum =
cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))
.toInt()
if (phoneNum > 0) {
val cursorPhone = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " =?",
arrayOf(id),
null
)
if (cursorPhone!!.count > 0) {
while (cursorPhone.moveToNext()) {
val phoneNumValue = cursorPhone.getString(
cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
)
contactsStr.add("$name|$phoneNumValue")
}
}
cursorPhone.close()
}
}
}
for (contact in contactsStr) {
val contactSplit = contact.split("|")
Log.i("CONTACT", contactSplit.toString())
contacts.add(Contact(contactSplit[0], contactSplit[1]))
}
}
private fun setAdapter() {
contactAdapter = ContactListAdapter(contacts)
binding.apply {
contactRecyclerView.layoutManager = LinearLayoutManager(this@MainActivity)
contactRecyclerView.adapter = contactAdapter
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val pos = viewHolder.adapterPosition
contacts.removeAt(pos)
contactAdapter.notifyItemRemoved(pos)
Toast.makeText(this@MainActivity, "Contact Deleted", Toast.LENGTH_LONG)
.show()
}
}).attachToRecyclerView(contactRecyclerView)
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val pos = viewHolder.adapterPosition
contacts.removeAt(pos)
contactAdapter.notifyItemRemoved(pos)
Toast.makeText(this@MainActivity, "Contact Archived", Toast.LENGTH_LONG)
.show()
}
}).attachToRecyclerView(contactRecyclerView)
}
}
companion object {
const val PERMISSION_REQ_READ_CONTACTS = 100
}
}
More Reference, Please click on the link: Content Provider
Happy Learning !