Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RecyclerView Not Updating with Ketch Library Downloads in Android #53

Open
v2arynice opened this issue Feb 17, 2025 · 0 comments
Open

Comments

@v2arynice
Copy link

I am using the Ketch library to manage downloads in my Android application. While downloads initiate successfully and appear in the notification bar, the associated RecyclerView does not update to reflect these downloads.

Steps to Reproduce:

  1. Fetch URL from Clipboard and Display Confirmation Dialog:
    • Retrieve a URL from the clipboard and display it in a MaterialDialog for user confirmation.
  2. Initiate Download:
    • Upon user confirmation, start the download using:
      ketch.download(linkClip, saveDir, fileName)
  3. Observe Downloads:
    • Monitor downloads with:
      ketch.observeDownloads()
          .flowOn(Dispatchers.IO)
          .collect { downloads ->
              adapterDownload.submitList(downloads)
          }
  4. Set Up RecyclerView:
    • Configure the RecyclerView with AdapterFile to display the filename and download progress.

Expected Behavior:
The RecyclerView should update in real-time to display active downloads and their progress.

Actual Behavior:
Despite successful download initiation and notification display, the RecyclerView remains empty or fails to update with new downloads.

Relevant Code:

HomeFragment:

@AndroidEntryPoint
class HomeFragment : BaseFragment<FragmentHomeBinding>() {
    override val bindingInflater: (LayoutInflater) -> FragmentHomeBinding
        get() = FragmentHomeBinding::inflate

    @Inject
    lateinit var adapterDownload: AdapterFile

    private lateinit var ketch: Ketch
    private val clipModel by viewModels<ClipBoardViewModel>()
    private var saveDir = ""

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = super.onCreateView(inflater, container, savedInstanceState)
        ketch = (requireContext().applicationContext as MyApp).ketch
        observeDownloads()
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Set save directory
        saveDir = requireContext().downloadDir(DOWNLOAD_DIR)

        // Observe clipboard data
        clipModel.clipData.observe(viewLifecycleOwner) { linkClip ->
            if (linkClip.isValidExtension()) {
                MaterialDialog(requireContext()).show {
                    customView(R.layout.add_download_file)
                    findViewById<TextInputEditText>(R.id.txt_link).apply {
                        text = Editable.Factory.getInstance().newEditable(linkClip)
                        isFocusable = false
                    }
                    findViewById<MaterialButton>(R.id.btn_positive).setOnClickListener {
                        val fileName = getFileNameFromUrl(linkClip) ?: ""
                        ketch.download(linkClip, saveDir, fileName) // Start download
                        dismiss()
                    }
                }
            }
        }

        // Set up RecyclerView adapter
        binding.listDownload.apply {
            adapter = adapterDownload
            layoutManager = LinearLayoutManager(requireContext())
        }
    }

    private fun observeDownloads() {
        viewLifecycleOwner.lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                ketch.observeDownloads()
                    .flowOn(Dispatchers.IO)
                    .collect { downloads ->
                        adapterDownload.submitList(downloads)
                    }
            }
        }
    }
}

AdapterFile:

class AdapterFile @Inject constructor() :
    ListAdapter<DownloadModel, AdapterFile.ViewHolder>(DiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemDownloadBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    inner class ViewHolder(private val binding: ItemDownloadBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(item: DownloadModel) {
            binding.titleName.text = item.fileName
            binding.progressBar.progress = item.progress
        }
    }

    class DiffCallback : DiffUtil.ItemCallback<DownloadModel>() {
        override fun areItemsTheSame(oldItem: DownloadModel, newItem: DownloadModel): Boolean =
            oldItem.id == newItem.id

        override fun areContentsTheSame(oldItem: DownloadModel, newItem: DownloadModel): Boolean =
            oldItem == newItem
    }
}

Questions/Requests:

  • Has anyone encountered a similar issue where the RecyclerView does not update despite active downloads?
  • Could this behavior be related to using Dispatchers.IO during download observation or threading issues?
  • Are there recommended changes or additional steps to ensure the adapter is properly notified of changes in the download list?

Any guidance or suggestions to resolve this issue would be greatly appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant