How to implement pagination in RecyclerView kotlin - kotlin

I want to implement load more in Recyclerview.
My onCreateView:
`
override fun onDashboard(body: BusinessModel?) {
val status: Int = body!!.status
val dataflow: Int = body.dataFlow
if (status == 1 && dataflow == 1) {
bindingFrag.shimmerViewContainer.stopShimmerAnimation()
bindingFrag.shimmerViewContainer.visibility = View.GONE
businessList.clear()
if (checkFavUn.equals("1")) {
bindingFrag.recyclerView.visibility = View.VISIBLE
bindingFrag.txtError.visibility = View.GONE
body.data?.let { businessList.addAll(it) }
adapter.notifyItemChanged(ind_pos)
} else {
bindingFrag.recyclerView.visibility = View.VISIBLE
bindingFrag.txtError.visibility = View.GONE
body.data?.let { businessList.addAll(it) }
adapter.notifyDataSetChanged()
}
} else if (status == 0 && dataflow == 0) {
bindingFrag.shimmerViewContainer.stopShimmerAnimation()
bindingFrag.shimmerViewContainer.visibility = View.GONE
bindingFrag.recyclerView.visibility = View.GONE
bindingFrag.txtError.visibility = View.VISIBLE
bindingFrag.txtError.text = body.message
}
}
`
How to implement pagination in RecyclerView on scroll?
I can't run the pagination function in my kotlin project.

Related

Loading state adapter is always loading

My task is to load recyclerView and show pagination which I both implemented.
I also implemented LoadingState for adapter.
ApiCall:
#GET("top-headlines?sources=bbc-news,techcrunch&apiKey=${BuildConfig.API_KEY}")
suspend fun getTopHeadlinesArticles(
#Query("page") page:Int = 1,
#Query("q") query: String,
) : Response<ArticleListResponse>
I wont show paging because it is working so I will jump to repository:
fun getSearchResult(query: String) =
Pager(
config = PagingConfig(
pageSize = 1,
maxSize = 20,
enablePlaceholders = false
),
pagingSourceFactory = { ArticlePaging(newsService, query)}
).flow
ViewModel:
#OptIn(ExperimentalCoroutinesApi::class)
val news = _currentQuery.flatMapLatest { query ->
articleRepository.getSearchResult(query).cachedIn(viewModelScope)
}
Fragment:
binding.recyclerViewTop.layoutManager = LinearLayoutManager(context)
binding.recyclerViewTop.adapter = adapter.withLoadStateHeaderAndFooter(
header = ArticleLoadStateAdapter { adapter.retry() },
footer = ArticleLoadStateAdapter { adapter.retry() }
)
lifecycleScope.launchWhenCreated {
viewModel.news.collect { articles ->
adapter.submitData(articles)
}
}
And LoadStateViewHolder in LoadStateAdapter:
init {
binding.buttonRetry.setOnClickListener {
retry.invoke()
}
}
fun bind(loadState: LoadState) {
binding.apply {
progressBar.isVisible = loadState is LoadState.Loading
buttonRetry.isVisible = loadState !is LoadState.Loading
textViewError.isVisible = loadState !is LoadState.Loading
}
}
I already predefined DEFAULT_QUERY so I only get 1 Article.
Problem is that progressBar loading is always visible and I have no more articles to show.
Edit: when i have at least 10 items to show this works fine
Edit 2nd: Add ArticlePagingSource if that can help
override fun getRefreshKey(state: PagingState<Int, ArticleResponse>): Int? {
return state.anchorPosition?.let {
val anchorPage = state.closestPageToPosition(it)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
try {
val currentPageList = params.key ?: 1
response = if(query != ""){
newsService.getTopHeadlinesArticles(currentPageList, query)
} else{
newsService.getTopHeadlinesArticles(currentPageList)
}
val responseList = mutableListOf<ArticleResponse>()
val data = response.body()?.articleResponses ?: emptyList()
responseList.addAll(data)
val prevKey = if (currentPageList == 1) null else currentPageList - 1
return LoadResult.Page(
responseList,
prevKey,
currentPageList.plus(1)
)

check network state in fragment in android

I defined two layers in a fragment, the display of which depends on the internet and gps on and off
There is no problem when the program runs, but when I enter another fragment and return to the first fragment, the code does not work properly.
onViewCreated
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//broadcast receiver for check runtime network
val registerReceiver = requireActivity().registerReceiver(
broadcastReceiver,
IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")
)
val registerReceiverr = requireActivity().registerReceiver(
broadcastReceiver,
IntentFilter("android.location.PROVIDERS_CHANGED")
)
}
broadcastReceiver
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Networkstate.isOnline(context) == false) {
binding.offlineRoot.visibility = View.VISIBLE
binding.onlineRoot.visibility = View.GONE
} else {
locationManager = requireActivity().getSystemService(AppCompatActivity.LOCATION_SERVICE) as LocationManager?
val statusOfGPS = locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER)
if (statusOfGPS == true) {
binding.offlineRoot.visibility = View.GONE
binding.onlineRoot.visibility = View.VISIBLE
binding.ongps.visibility = View.VISIBLE
binding.offgps.visibility = View.GONE
} else {
binding.offlineRoot.visibility = View.GONE
binding.onlineRoot.visibility = View.VISIBLE
binding.ongps.visibility = View.GONE
binding.offgps.visibility = View.VISIBLE
}
}
}
}

Choose file in external storage and get path

i know this question has been asked several times but everything i can find is only in Java and not very relevant to me...
I'm trying to select a file when i click on a button in my app (images or videos like : /storage/emulated/0/Download/giphy.gif ) and the when the picture or video is selected, i need the path to go inside an edittext.
I have found that code in kotlin for path :
class URIPathHelper {
fun getPath(context: Context, uri: Uri): String? {
val isKitKatorAbove = true
// DocumentProvider
if (isKitKatorAbove && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
}
} else if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).toTypedArray()
val type = split[0]
var contentUri: Uri? = null
if ("image" == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
}
} else if ("content".equals(uri.scheme, ignoreCase = true)) {
return getDataColumn(context, uri, null, null)
} else if ("file".equals(uri.scheme, ignoreCase = true)) {
return uri.path
}
return null
}
fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
cursor = uri?.let { context.getContentResolver().query(it, projection, selection, selectionArgs,null) }
if (cursor != null && cursor.moveToFirst()) {
val column_index: Int = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
}
} finally {
if (cursor != null) cursor.close()
}
return null
}
fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
}
And this is what i'm trying :
binding.redloader.setOnClickListener {
val uriPathHelper = URIPathHelper()
val filePath: String? = uriPathHelper.getPath(this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
val uri: Uri = Uri.parse(filePath)
val intent = Intent(Intent.ACTION_VIEW)
intent.type = "image/*"
intent.putExtra(Intent.ACTION_VIEW, uri)
startActivity(Intent.createChooser(intent, "Open file"))
binding.redgif.setText(filePath)
}
When I click on the button it automatically chooses the first picture in the storage, and then it opens google picture but I cannot do anything except watch the pictures...
I'm sorry I know they are some stupid things in my code, I think I have something to do with intent but all I see on the internet is calling private void and it is not working for me...
I'm a complete beginner and I really hope someone can help me...
Update with what i'm trying, i think i'm close :
binding.redloader.setOnClickListener {
val uriPathHelper = URIPathHelper()
intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent = Intent.createChooser(intent, "Choose a file")
val resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
if (data != null) {
val fileUri: Uri? = data.data
Log.i(LOG_TAG, fileUri.toString())
var fileURIPathHelper: String? = null
try {
fileURIPathHelper = uriPathHelper.getPath(this, EXTERNAL_CONTENT_URI)
} catch (e: Exception) {
Log.e(LOG_TAG, "Error: " + e)
Toast.makeText(this, "Error: " + e, Toast.LENGTH_SHORT).show()
}
this.binding.redgif.setText(fileURIPathHelper)
}
}
}
resultLauncher.launch(intent)
}
I solved it ! :)
val resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
if (data != null) {
val fileUri: Uri? = data.data
Log.i(PackageManagerCompat.LOG_TAG, fileUri.toString())
val contentUri: String?
try {
contentUri = uriPathHelper.getPath(this, fileUri!!)
this.binding.redgif.setText(contentUri)
} catch (e: Exception) {
Log.e(PackageManagerCompat.LOG_TAG, "Error: " + e)
Toast.makeText(this, "Error: " + e, Toast.LENGTH_SHORT).show()
}
}
}
}
binding.redloader.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
startActivity(Intent.createChooser(intent, "Open file"))
resultLauncher.launch(intent)
}

ActivityResultLauncher not working with fragment?

I'm writing an app using Kotlin.
I'am using ActivityResultLauncher for get permission. I can use ActivityResultLauncher on Activity clearly but when I try to get permission on fragment with ActivityResultLauncher, the app goint to background without getting any error. I will put my code below. Please help me :)
private var selectedPictureUri: Uri? = null
private lateinit var permissionLauncherForGallery: ActivityResultLauncher<String>
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
override fun populateUI(savedInstanceState: Bundle?) {
setClickListener()
registerLauncher()
}
private fun selectMedia() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
//request permission
if (ActivityCompat.shouldShowRequestPermissionRationale(
this#WriteUsActivity,
Manifest.permission.READ_EXTERNAL_STORAGE
)
) {
Snackbar.make(
mBinding!!.root,
"Permission needed for Gallery",
Snackbar.LENGTH_INDEFINITE
).setAction("Give Permission") {
permissionLauncherForGallery.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
}.show()
} else {
permissionLauncherForGallery.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
}
} else {
val intentToGallery =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
activityResultLauncher.launch(intentToGallery)
}
}
private fun registerLauncher() {
activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
val intentFromResult = result.data
if (intentFromResult != null) {
selectedPictureUri = intentFromResult.data
if (selectedPictureUri != null) {
mBinding?.ivPhoto?.visibility= View.VISIBLE
mBinding?.ivPhoto?.setImageURI(selectedPictureUri)
} else {
val bundle = result.data!!.extras
val bitmap = bundle?.get("data")
mBinding?.ivPhoto?.setImageBitmap(bitmap as Bitmap)
}
}
}
}
permissionLauncherForGallery =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
if (result) {
//permission granted
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
val intentToGallery =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
activityResultLauncher.launch(intentToGallery)
}
} else {
//permission denied
Toast.makeText(this, "Permisson needed!", Toast.LENGTH_LONG).show()
}
}
}
private fun setClickListener() {
mBinding?.apply {
btnPhoto.setOnClickListener {
selectMedia()
}
btnPhoto2.setOnClickListener {
this#WriteUsActivity.toast("Pick Second Photo")
}
btnSend.setOnClickListener {
this#WriteUsActivity.toast("Save")
}
}
}

mediaPlayer crash when using mediaPlayer.release()

we have RecyclerView with list of children songs, when you click on a song it takes you to another activity mediaPlayer.. The problem is that when I play a song and then use back bottom the song stop and that is ok, and application stop this is the problem, but when I comment //mediaPlayer.release() the application works well it didn't crash and the song only stop when I go back, but the problem is that when I choose another song from RecyclerView and click PlayBotton the song starts from the start but the SeekBar seeks to the end and don't move. does any body have idea how to solve this?
I tried to but mediaPlayer.release() between Try and Catch but the problem still the same.
class ChildrenSongsPreview : AppCompatActivity() {
private var handler = Handler()
var mediaPlayer: MediaPlayer? = null
private var startTime = 0.0
private var finalTime = 0.0
private var updateSongTime = object : Runnable {
override fun run() {
startTime = mediaPlayer?.currentPosition!!.toDouble()
txt_playing_duration.text = String.format(
"%d:%d", TimeUnit.MILLISECONDS.toMinutes(startTime.toLong()),
TimeUnit.MILLISECONDS.toSeconds(startTime.toLong()) -
TimeUnit.MINUTES.toSeconds(
TimeUnit.MILLISECONDS.toMinutes(startTime.toLong())
)
)
songs_seekbar.progress = startTime.toInt()
handler.postDelayed(this, 100)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_children_songs_preview)
var pos = intent.getIntExtra("KEY_SONG", 0)
var song_ID: Int = R.raw.zahab_elel
when (pos) {
0 -> {
song_ID = R.raw.mama_zmanha_gaya
txt_song_name_preview.text = "ماما زمانها جاية"
}
1 -> {
song_ID = R.raw.zahab_elel
txt_song_name_preview.text = "ذهب الليل"
}
2 -> {
song_ID = R.raw.gdo_ali
txt_song_name_preview.text = "جدو علي"
}
3 -> {
song_ID = R.raw.ebre2_shay
txt_song_name_preview.text = "إبريق الشاي"
}
}
var position = 0
mediaPlayer = MediaPlayer.create(this, song_ID)
//set song duration
finalTime = mediaPlayer?.duration!!.toDouble()
txt_song_duration.text = String.format(
"%d:%d",
TimeUnit.MILLISECONDS.toMinutes(finalTime.toLong()),
TimeUnit.MILLISECONDS.toSeconds(finalTime.toLong()) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(finalTime.toLong()))
)
btn_play.setOnClickListener {
mediaPlayer?.seekTo(position)
mediaPlayer?.start()
btn_play.visibility = View.GONE
btn_pause.visibility = View.VISIBLE
if (oneTimeOnly == 0) {
songs_seekbar!!.max = finalTime.toInt()
oneTimeOnly = 1
}
songs_seekbar!!.progress = startTime.toInt()
handler.postDelayed(updateSongTime, 100)
}
btn_pause.setOnClickListener {
position = mediaPlayer?.currentPosition!!
mediaPlayer?.pause()
btn_pause.visibility = View.GONE
btn_play.visibility = View.VISIBLE
}
btn_stop.setOnClickListener {
mediaPlayer?.stop()
position = 0
btn_pause.visibility = View.GONE
btn_play.visibility = View.VISIBLE
mediaPlayer = MediaPlayer.create(this, song_ID)
}
mediaPlayer?.setOnCompletionListener {
position = 0
btn_pause.visibility = View.GONE
btn_play.visibility = View.VISIBLE
mediaPlayer = MediaPlayer.create(this, song_ID)
}
songs_seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, p: Int, fromUser: Boolean) {
if (fromUser) {
position = p
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
mediaPlayer?.seekTo(position)
}
})
}
override fun onDestroy() {
super.onDestroy()
mediaPlayer?.stop()
mediaPlayer?.release()
}
companion object {
var oneTimeOnly = 0
}
}
Media player instance should also be released in onDestroy()
override fun onDestroy() {
mediaPlayer?.release()
mediaPlayer = null
super.onDestroy()
}