I have a code to retrieve list of all music from storage but after i renamed a file the recyclerview doesnt update with the change
even after deleting a file it still remains the same
fun Context.musicFiles():MutableList{
val list:MutableList<Music> = mutableListOf()
val uri: Uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
//val uri: Uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI
// IS_MUSIC : Non-zero if the audio file is music
val selection = MediaStore.Audio.Media.IS_MUSIC + "!= 0"
// Sort the musics
val sortOrder = MediaStore.Audio.Media.TITLE + " ASC"
//val sortOrder = MediaStore.Audio.Media.TITLE + " DESC"
// Query the external storage for music files
val cursor: Cursor = this.contentResolver.query(
uri, // Uri
null, // Projection
selection, // Selection
null, // Selection arguments
sortOrder // Sort order
)
// If query result is not empty
if (cursor!= null && cursor.moveToFirst()){
val id:Int = cursor.getColumnIndex(MediaStore.Audio.Media._ID)
val title:Int = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE)
val artist:Int= cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)
val musicpathh:Int= cursor.getColumnIndex(MediaStore.Audio.Media.DATA)
val album:Int = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM)
// Now loop through the music files
do {
val audioId:Long = cursor.getLong(id)
val audioTitle:String = cursor.getString(title)
val audioArtist:String = cursor.getString(artist)
val audiopath:String = cursor.getString(musicpathh)
val audioalbum:String = cursor.getString(album)
// Add the current music to the list
list.add(Music(audioId,audioTitle,audioArtist,audiopath,audioalbum))
}while (cursor.moveToNext())
}
// Finally, return the music files list
return list
}
data class Music(val id:Long, val title:String, val artist:String, val audiopath:String, val audioalbumm:String)
Function to get musicfiles
val list:MutableList = musicFiles()
val titles = mutableListOf<String>()
val artist = mutableListOf<String>()
val musicpath = mutableListOf<String>()
val album = mutableListOf<String>()
val checkd = mutableListOf<Boolean>()
for (music in list){titles.add(music.title)}
for (music in list){artist.add(music.artist)}
for (music in list){musicpath.add(music.audiopath)}
for (music in list){album.add(music.audioalbumm)}
for (music in list){checkd.add(false)}
val adapter= HobbiesAdapter(this, titles, artist, musicpath, album, checkd)
recyclerView.adapter = adapter
adapter
class HobbiesAdapter(val context: Context, val hobbies: MutableList, val artis: MutableList, val pathh: MutableList, val albumm: MutableList, val checkd: MutableList) : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false)
return MyViewHolder(view)
}
override fun getItemCount(): Int {
return hobbies.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val hobby = hobbies[position]
val artistt = artis[position]
val patth = pathh[position]
val albbum = albumm[position]
holder.setData(hobby, artistt, patth, position, albbum)
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var currentHobby: String = ""
var currentArtist: String = ""
var currentPath: String = ""
var currentAlbum: String = ""
var currentPosition: Int = 0
var checkdd:Int=0
var currentCheckedStatus:Boolean=false
init {
itemView.setOnClickListener {
if(itemView.checkstatus.isChecked==true){
itemView.checkstatus.isChecked=false
checkdd=adapterPosition
checkd.set(checkdd,false)
}
else{
itemView.checkstatus.isChecked=true
checkdd=adapterPosition
checkd.set(checkdd,true)
}
}
itemView.checkstatus.setOnClickListener {
if(itemView.checkstatus.isChecked==true){
itemView.checkstatus.isChecked=false
checkdd=adapterPosition
checkd.set(checkdd,false)
}
else{
itemView.checkstatus.isChecked=true
checkdd=adapterPosition
checkd.set(checkdd,true)
}
}
}
fun setData(hobby: String, artiist: String, paath: String, pos: Int, albuum: String) {
itemView.txvTitle.text = hobby
itemView.txvArtist.text=artiist
itemView.txvPath.text=paath
itemView.txvAlbum.text=albuum
itemView.checkstatus.isChecked=checkd.get(pos)
this.currentHobby = hobby
this.currentArtist = artiist
this.currentPath = paath
this.currentAlbum = albuum
this.currentPosition = pos
this.currentCheckedStatus=checkd.get(pos)
}
}
}
Related
i am trying to create a video player app using kotlin , First of all I got the videos files by using MediaStore , than store this in ArrayList so far it's been perfect but When I made a folder list of videos, I tried to find out the size of those folders and how many video files there are in those folders, but I failed. like this (Image)
Check this image for more clear
This is my data class code (VideoItem.Kt)
import android.net.Uri
data class VideoItem(
val id: String,
val title: String,
val duration: Long = 0,
val folderName: String,
val size: String,
val path: String,
val dateAdded: String,
val artUri: Uri
)
data class FolderItem(
val id: String,
val folderName: String,
val folderSize: Long
)
This is my MainActivity Code To get Allvideos Using MediaStore
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
companion object {
lateinit var videoList: ArrayList<VideoItem>
lateinit var folderList: ArrayList<FolderItem>
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
folderList = ArrayList()
videoList = getAllVideos()
setFragment(VideoviewFragment())
}
private fun setFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.FrameLayout, fragment)
transaction.disallowAddToBackStack()
transaction.commit()
}
#SuppressLint("Recycle", "Range")
private fun getAllVideos(): ArrayList<VideoItem> {
val tempList = ArrayList<VideoItem>()
val tempFolderList = ArrayList<String>()
val projection = arrayOf(
MediaStore.Video.Media.TITLE,
MediaStore.Video.Media.SIZE,
MediaStore.Video.Media._ID,
MediaStore.Video.Media.BUCKET_DISPLAY_NAME,
MediaStore.Video.Media.DATA,
MediaStore.Video.Media.DATE_ADDED,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.BUCKET_ID
)
val cursor = this.contentResolver.query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
MediaStore.Video.Media.DATE_ADDED + " DESC"
)
if (cursor != null)
if (cursor.moveToNext())
do {
val titleC =
cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE))
val idC = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media._ID))
val folderNameC =
cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_DISPLAY_NAME))
val folderIdC =
cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_ID))
val sizeC = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.SIZE))
val pathC = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA))
val dateAddedC =
cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATE_ADDED))
val durationC =
cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DURATION))
.toLong()
try {
val file = File(pathC)
val artUriC = Uri.fromFile(file)
val video = VideoItem(
title = titleC,
id = idC,
folderName = folderNameC,
size = sizeC,
path = pathC,
duration = durationC,
dateAdded = dateAddedC,
artUri = artUriC
)
if (file.exists()) tempList.add(video)
//for adding Folders
if (!tempFolderList.contains(folderNameC)) {
tempFolderList.add(folderNameC)
val folderSizeC = getFileLength(pathC)
folderList.add(
FolderItem(
id = folderIdC,
folderName = folderNameC,
folderSize = folderSizeC
)
)
}
} catch (_: Exception) {
}
} while (cursor.moveToNext())
cursor?.close()
return tempList
}
private fun getFileLength(path: String?): Long {
return if (!isExistFile(path)) 0 else File(path.toString()).length()
}
private fun isExistFile(path: String?): Boolean {
val file = File(path.toString())
return file.exists()
}
}
This is my RecyclerviwAdapter Code(FolderAdapter.kt)
class FoldersAdapter(private val context: Context, private var foldersList: ArrayList<FolderItem>) :
RecyclerView.Adapter<FoldersAdapter.MyHolder>() {
class MyHolder(binding: FolderItemBinding) : RecyclerView.ViewHolder(binding.root) {
val folderName = binding.folderName
val noofFiles = binding.nooffiles
val folderSize = binding.foldersize
val root = binding.root
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
return MyHolder(FolderItemBinding.inflate(LayoutInflater.from(context), parent, false))
}
override fun onBindViewHolder(holder: MyHolder, position: Int) {
holder.folderName.text = foldersList[position].folderName
val size: Long = foldersList[position].folderSize
holder.folderSize.text = android.text.format.Formatter.formatFileSize(context, (size))
holder.root.setOnClickListener {
val intent = Intent(context, FolderVideosActivity::class.java)
intent.putExtra("position", position)
ContextCompat.startActivity(context, intent, null)
}
}
override fun getItemCount(): Int {
return foldersList.size
}
}
This is my all codes now please check out all code and suggest the best.
Thank you
Use this function for size
private fun getFolderSize(f: File): Long {
var size: Long = 0
if (f.isDirectory) {
for (file in f.listFiles()!!) {
size += getFolderSize(file)
}
} else {
size = f.length()
}
return size
}
And Count number of files Use this
val length = File("/path/to/folder").listFiles()?.size
I am making a small music player, I want to make the typical recyclerview that shows all the songs that are on the device. The problem is that I'm very new to using MediaStore and I don't really understand how it works. I have read the documentation and several articles, but I can't understand it very well. This is what I have done for the moment and I don't know if it is enough or if something is missing. I would be grateful if someone could show me how to achieve what I want to do.
MAIN ACTIVITY:
class MainActivity : AppCompatActivity() {
private lateinit var mBinding : ActivityMainBinding
private lateinit var mSongAdapter : SongAdapter
private lateinit var mLinearLayoutManager : LinearLayoutManager
private var mSongs = listOf<Song>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(mBinding.root)
initSongs()
initRecycler()
}
override fun onStop() {
super.onStop()
Log.i("Canciones:", mSongs.toString())
}
private fun initSongs() {
GlobalScope.launch{
mSongs = querySongs()
}
}
private fun initRecycler() {
mSongAdapter = SongAdapter(mSongs)
mLinearLayoutManager = LinearLayoutManager(this)
mBinding.rvCanciones.apply {
setHasFixedSize(true)
layoutManager = mLinearLayoutManager
adapter = mSongAdapter
}
}
private suspend fun querySongs() : List<Song> {
val songs = mutableListOf<Song>()
withContext(Dispatchers.IO){
val projection = arrayOf(
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.SIZE
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
application.contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null
)?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)
val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
val durationColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)
val sizeColum = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)
while (cursor.moveToNext()){
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
val duration = cursor.getFloat(durationColumn)
val size = cursor.getString(sizeColum)
val contentUri = ContentUris.withAppendedId(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
id
)
val song = Song(contentUri, name, duration, size)
songs += song
}
}
} else {
}
}
return songs
}
}
SONG DATA CLASS:
data class Song(
val uri : Uri,
val name : String,
val duration : Float,
val size : String
)
I am using a custom adapter to display a list of contacts on AutoTextComplete but when I try to run it I get the error "kotlin.Unit cannot be cast to java.util.List" for
mContact = filterResults.values **as List<Contact>**
Contact is a Serializable object and is how i am retrieving contact names as objects in the List - code is below... I have tried looking for a solution elsewhere, but have not been able to resolve... if you can redirect or solution or guide will be amazing thanks
private var invoice: Invoice? = null
private lateinit var contact: Contact
private var invoiceItems: List<InvoiceItems>? = null
private lateinit var contactSelect: ArrayList<Contact>
private lateinit var dueDate: Calendar
private val calendar = Calendar.getInstance()
private var total = 0
private var subTotal = 0
private var taxrate = 0
private var invoiceType: String = ""
private var invoiceUpdt: InvoiceItems? = null
private var j: String? = null
private var clientLkey: String? = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit_invoice)
val toolbar: Toolbar = findViewById(R.id.toolbar_editinv)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowHomeEnabled(true)
val invoiceClient = findViewById<AutoCompleteTextView>(R.id.invoiceClient)
val invoiceDueDt = findViewById<TextView>(R.id.invoiceDueDt)
dueDate = Calendar.getInstance()
//getting values from intent
invoice = intent.getSerializableExtra("invoice") as? Invoice
invoiceItems = intent.getSerializableExtra("invoiceItem") as? List<InvoiceItems>
invoiceUpdt = intent.getSerializableExtra("invoiceItemUpdt") as? InvoiceItems
j = intent.getStringExtra("i")
if (invoice == null){
invoiceType = "new"
supportActionBar?.title = "Add Invoice"
addinvoiceItem()
} else {
editInvoice()
}
//Setup Due date for the invoice
invoiceDueDt.setOnClickListener {
showCalendar()
}
//Auto complete based on database for selecting the client
val clientContact: List<Contact> = ArrayList<Contact>()
val adapter = ClientSelectAdapter(this, R.layout.userlatomcontacts, clientContact)
invoiceClient.setAdapter(adapter)
invoiceClient.threshold = 2
invoiceClient.setOnItemClickListener { parent, _, position, id ->
val selectedClient = parent.adapter.getItem(position) as Contact?
invoiceClient.setText(selectedClient?.name)
clientLkey = selectedClient?.lookupKey
}
}
inner class ClientSelectAdapter(
context: Context,
#LayoutRes private val layoutResource: Int,
private var allContacts: List<Contact>
):
ArrayAdapter<Contact>(context, layoutResource, allContacts),
Filterable {private var mContact: List<Contact> = allContacts
override fun getCount(): Int {
return mContact.size
}
override fun getItem(p0: Int): Contact {
return mContact[p0]
}
override fun getItemId(p0: Int): Long {
// Or just return p0
return mContact[p0].id.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var view = convertView
if (view == null) {
view = LayoutInflater.from(parent.context)
.inflate(layoutResource, parent, false)
}
val invoiceClient = view!!.findViewById<View>(R.id.invoiceClient) as TextView
invoiceClient.text = mContact[position].name
val clientProfile = view.findViewById<View>(R.id.profile_image) as ShapeableImageView
Picasso.get().load(mContact[position].photoUri)
.placeholder(R.drawable.ic_baseline_whatshot_24).fit().centerCrop()
.into(clientProfile)
return view
}
override fun getFilter(): Filter {
return object : Filter() {
override fun publishResults(
charSequence: CharSequence?,
filterResults: FilterResults
) {
**mContact = filterResults.values as List<Contact>**
notifyDataSetChanged()
}
override fun performFiltering(charSequence: CharSequence?): FilterResults {
val queryString = charSequence?.toString()?.toLowerCase(Locale.ROOT)
val results = FilterResults()
results.values = if (queryString == null || queryString.isEmpty())
allContacts
else {
val db = AppDatabase.getDatabase(context)
allContacts = db.contactsDao().getBySearch(queryString)
}
return results
}
}
}
}
According to kotlin documentations Branches of if branches can be blocks. In this case, the last expression is the value of a block
So, in your case, when code enters the else block, the last expression is assignment, and assignments return Unit in kotlin. You may check this situation with this simple example:
var temp = 0
var result: Int = if (temp > 0) {
5
} else {
temp = 5
}
You would see the ide error at temp = 5 since it returns Unit whereas result expects Int.
To sum up, you just need to change your else block as follows:
else {
val db = AppDatabase.getDatabase(context)
allContacts = db.contactsDao().getBySearch(queryString)
allContacts
}
I'm trying to build a single fragment(inside an activity ofcourse) application, which displays all the messages like the default messages app. There is a recyclerview in a MessageFragment. MessageRecyclerViewAdapter is the adapter for the same. I think the culprit is MessageRecyclerViewAdapter. mValues will have a map of id to sms. But the keys are being removed mValues as soon as the viewholder is detached or recycled. So, I think all the references to sms are being removed when it's removed from recycler view, but the memory keeps on increasing almost linearly as I scroll down and results in OOM. What am I missing? (I'm a backend developer, learning android for context)
class MessageRecyclerViewAdapter(
private val mListener: OnListFragmentInteractionListener?,
private val recyclerView: RecyclerView,
val context: Context
) : RecyclerView.Adapter<MessageRecyclerViewAdapter.MessageViewHolder>() {
private val mOnClickListener: View.OnClickListener
private var mValues: LinkedHashMap<Int, Sms> = LinkedHashMap()
private var mPositionToIdMap: MutableMap<Int, Int> = mutableMapOf()
private var count: Int? = null
init {
mOnClickListener = View.OnClickListener { v ->
val id = v.tag as Int
// Notify the active callbacks interface (the activity, if the fragment is attached to
// one) that an item has been selected.
mListener?.onListFragmentInteraction(mValues[id])
}
}
fun setCount(count: Int) {
this.count = count
}
override fun onCreateViewHolder(parent: ViewGroup, position: Int): MessageViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.fragment_message, parent, false)
return MessageViewHolder(view, position)
}
//This will pass position to onCreateViewHolder, instead of viewtype
override fun getItemViewType(position: Int): Int = position
override fun onBindViewHolder(holderMessage: MessageViewHolder, position: Int) {
val sms: Sms? = mValues.get(mPositionToIdMap[position])
if (sms == null) {
Log.e("MRVA", "sms == null")
return
}
val addressText = String.format("%s (%s), id:%s, %s", sms.address, DateTimeUtil.format(sms.date), sms._id, position)
Log.e("addressText", addressText)
holderMessage.mAddressView.text = addressText
with(holderMessage.mView) {
tag = sms._id
setOnClickListener(mOnClickListener)
}
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
mValues = linkedMapOf()
mPositionToIdMap = linkedMapOf()
}
override fun onViewDetachedFromWindow(holder: MessageViewHolder) {
super.onViewDetachedFromWindow(holder)
remove(holder.mPosition)
}
override fun onViewRecycled(holder: MessageViewHolder) {
super.onViewRecycled(holder)
remove(holder.mPosition)
}
fun add(
sms: Sms,
id: Int,
position: Int
) {
mValues[id] = sms
mPositionToIdMap[position] = id
}
fun remove(mPosition: Int) {
mValues.remove(mPositionToIdMap[mPosition])
mPositionToIdMap.remove(mPosition)
}
override fun getItemCount(): Int = count ?: 0
fun getId(position: Int): Int? = mPositionToIdMap[position]
fun hasData(position: Int): Boolean = mPositionToIdMap.containsKey(position)
fun getBottomMostPositionWithData(): Int {
var position = 0
mPositionToIdMap.forEach { entry ->
position = entry.key
}
return position
}
fun getTopMostPositionWithData() = mPositionToIdMap.iterator().next().key
fun get(id: Int) = mValues[id]
inner class MessageViewHolder(val mView: View, position: Int) : RecyclerView.ViewHolder(mView) {
val mAddressView: TextView = mView.address
val mPosition = position
}
}
class SmsUtil {
private final val CONTENT_URI: String = "content://sms/inbox"
fun readAllMessages(
context: Context?,
epoch: Long? = null,
limit: Int? = null,
smsHandler: SmsHandler
) {
val cursor = getCursor(context, epoch, limit) ?: return
processSms(cursor, smsHandler)
}
private fun processSms(
cursor: Cursor?,
smsHandler: SmsHandler
) {
if (cursor == null)
return
try {
if (cursor.moveToFirst()) {
do {
val sms = getSms(cursor)
Log.v(ContentValues.TAG, "SMS read $sms")
smsHandler.handle(sms)
} while (cursor.moveToNext())
} else {
Log.v(ContentValues.TAG, "The user does not have any sms")
}
}catch (e: Exception) {
} catch (e: Error) {
} finally {
cursor.close()
}
}
private fun getCursor(context: Context?, epoch: Long? = null, limit: Int? = null): Cursor? {
val selection = if (epoch != null) String.format("%s > %s", Sms.COLUMN_DATE, epoch) else null
val sortOrder =
if (limit != null) String.format("%s desc limit %s ", Sms.COLUMN_DATE, limit) else null
//above will be compiled into sql . SELECT * FROM sms_restricted WHERE (type=1) AND (_id > 100) ORDER BY limit 100
return context?.contentResolver
?.query(Uri.parse(CONTENT_URI), null, selection, null, sortOrder)
}
private fun getSms(cursor: Cursor?): Sms? {
if (cursor == null)
return null
val sms = Sms()
sms._id =
cursor.getInt(cursor.getColumnIndexOrThrow(Sms.COLUMN_ID))
sms.threadId =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_THREAD_ID))
sms.address =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_ADDRESS))
sms.person =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_PERSON))
sms.date =
cursor.getLong(cursor.getColumnIndexOrThrow(Sms.COLUMN_DATE))
sms.dateSent =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_DATE_SENT))
sms.protocol =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_PROTOCOL))
sms.read =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_READ))
sms.status =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_STATUS))
sms.type =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_TYPE))
sms.replyPathPresent =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_REPLY_PATH_PRESENT))
sms.subject =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_SUBJECT))
sms.body =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_BODY))
sms.serviceCenter =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_SERVICE_CENTER))
sms.locked =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_LOCKED))
sms.errorCode =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_ERROR_CODE))
sms.seen =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_SEEN))
sms.subId =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_SUB_ID))
sms.creator =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_CREATOR))
sms.priority =
cursor.getString(cursor.getColumnIndexOrThrow(Sms.COLUMN_PRIORITY))
return sms
}
fun getCount(context: Context?): Int {
val cursor = getCursor(context) ?: return 0
val count = cursor.count
cursor.close()
return count
}
fun getLatestMessages(
context: Context?,
epoch: Long? = null,
limit: Int? = null,
smsHandler: SmsHandler
) {
if (context == null)
return
val selection = if (epoch != null) String.format("%s > %s", Sms.COLUMN_DATE, epoch) else null
val sortOrder =
if (limit != null) String.format("%s asc limit %s ", Sms.COLUMN_DATE, limit) else null
val cursor = context.contentResolver
?.query(Uri.parse(CONTENT_URI), null, selection, null, sortOrder)
processSms(cursor, smsHandler)
}
fun getOldestMessages(
context: Context?,
epoch: Long? = null,
limit: Int? = null,
smsHandler: SmsHandler
) {
if (context == null)
return
val selection = if (epoch != null) String.format("%s < %s", Sms.COLUMN_DATE, epoch) else null
val sortOrder = String.format("%s desc limit %s ", Sms.COLUMN_DATE, limit)
val cursor = context.contentResolver
?.query(Uri.parse(CONTENT_URI), null, selection, null, sortOrder)
processSms(cursor, smsHandler)
}
}
I am trying to read contacts from ContactsContract in Kotin. But it's not showing any of the contact in the recyclerview. The noticeable thing is that the java version of this code is working fine.
So, I here is my Kotlin code for reading the contact:
private var adapter: ContactsAdapter? = null
private var myContacts : MutableList<MyContacts> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// code for recyclerview and adapter and checkPermission
val itemDecoration = DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
recycler_view.layoutManager = LinearLayoutManager(this)
recycler_view.addItemDecoration(itemDecoration)
adapter = ContactsAdapter(myContacts)
recycler_view.hasFixedSize()
recycler_view.adapter = ContactsAdapter(myContacts)
checkPermission()
}
private fun loadContactFromProvider() {
showProgressBar()
val contentResolver = contentResolver
val cursor = contentResolver.query(CONTENT_URI, null, null, null, DISPLAY_NAME)
if (cursor != null && cursor.count > 0) {
while (cursor.moveToNext()) {
val id = cursor.getString(cursor.getColumnIndex(ID))
val name = cursor.getString(cursor.getColumnIndex(DISPLAY_NAME))
val hasPhoneNumber = cursor.getInt(cursor.getColumnIndex(HAS_PHONE_NUMBER))
val contacts = MyContacts()
if (hasPhoneNumber > 0) {
contacts.contactName = name
val phoneCursor = contentResolver.query(PHONE_URI, arrayOf(NUMBER), "$PHONE_ID = ?", arrayOf(id), null)
val phoneNumbers = ArrayList<String>()
phoneCursor!!.moveToFirst()
while (!phoneCursor.isAfterLast) {
val phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER)).replace(" ", "")
phoneNumbers.add(phoneNumber)
phoneCursor.moveToNext()
}
contacts.contactNumber = phoneNumbers
phoneCursor.close()
}
val inputStream = ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, ContentUris.withAppendedId(CONTENT_URI, id.toLong()))
if (inputStream != null) {
val bitmap = BitmapFactory.decodeStream(inputStream)
contacts.contactImage = bitmap?.toString()
} else {
contacts.contactImage = vectorDrawableToBitmap(R.drawable.ic_person)?.toString()
}
log(contacts.contactName + " " + contacts.contactNumber.toString() + " " + contacts.contactImage.toString())
myContacts.add(contacts)
}
adapter?.notifyDataSetChanged()
cursor.close()
}
}
The log details are also fine, they are showing the full contact list. But I am unable to see it in the recyclerview. The constant field like ID, DISPLAY_NAME etc. are already defined in the companion object.
Kotlin code for RecyclerViewAdapter is:
class ContactsAdapter(private val contactList: MutableList<MyContacts>): RecyclerView.Adapter<ContactsAdapter.ContactViewHolder>() {
override fun onCreateViewHolder(viewGroup: ViewGroup, position: Int): ContactViewHolder {
val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.contact_item_layout,viewGroup,false)
return ContactViewHolder(view)
}
override fun onBindViewHolder(holder: ContactViewHolder, position: Int) {
val contact = contactList[position]
holder.name!!.text = contact.contactName
holder.mobile!!.text = contact.contactNumber[0]
Glide.with(holder.itemView.context)
.load(contact.contactImage)
.into(holder.image)
}
override fun getItemCount(): Int = contactList.size
class ContactViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
var image : ImageView = itemView.find(R.id.contact_image) as ImageView
var name : TextView? = itemView.find(R.id.contact_name) as TextView
var mobile : TextView? = itemView.find(R.id.contact_mobile) as TextView
}
}
Any help would be appreciated.
Thankyou