Fabian Speck
Fabian Speck

Reputation: 11

How to send images out of database from fragment to fragment in Android Studio using Glide

I try to send an image that is stored in the database from one fragment to the other. In the first one (using a recyclerview) it gets displayed, but in the second one (normal fragment) it doesnt work and i get a permission error. I have given the required permissions in the manifest (otherwise it wouldnt work in the recyclerview).

Here it works fine:

package com.example.travelfriends.data

import android.net.Uri
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.travelfriends.R

class BookAdapter(
    private val books: List<Book>,
    private val onBookClick: (Book) -> Unit
) : RecyclerView.Adapter<BookAdapter.BookViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_book, parent, false)
        return BookViewHolder(view)
    }

    override fun onBindViewHolder(holder: BookViewHolder, position: Int) {
        val book = books[position]
        holder.bookTitle.text = book.name
        holder.bookDescription.text = book.description

        Log.d("Glide", "Context available: ${holder.itemView.context}")
        Log.d("Glide", "Loading image from URI: ${book.image}")

        // Verwende Glide, um das Bild zu laden
        Glide.with(holder.itemView.context)
            .load(Uri.parse(book.image))
            .placeholder(R.drawable.ic_launcher_foreground)
            .error(R.drawable.ic_launcher_foreground)
            .into(holder.bookImage)

        holder.itemView.setOnClickListener {
            onBookClick(book)
        }
    }

    override fun getItemCount(): Int {
        return books.size
    }

    // ViewHolder für jedes Buch
    class BookViewHolder(view: android.view.View) : RecyclerView.ViewHolder(view) {
        val bookTitle: TextView = view.findViewById(R.id.tvRecViewBookTitle)
        val bookDescription: TextView = view.findViewById(R.id.tvRecViewBookDescription)
        val bookImage: ImageView = view.findViewById(R.id.ivRecViewBookImage)
    }

}
package com.example.travelfriends.ui.fragments

import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.travelfriends.R
import com.example.travelfriends.data.AppViewModel
import com.example.travelfriends.data.BookAdapter
import com.example.travelfriends.data.Question


class LibraryShowBooksFragment : Fragment() {


    private lateinit var appViewModel: AppViewModel
    private lateinit var recyclerView: RecyclerView
    private lateinit var bookAdapter: BookAdapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_library_show_books, container, false)

        recyclerView = view.findViewById(R.id.recyclerViewBooks)
        recyclerView.layoutManager = LinearLayoutManager(requireContext())

        appViewModel = ViewModelProvider(requireActivity())[AppViewModel::class.java]

        //Alle Bücher laden
        appViewModel.getAllBooks()

        // Lade alle Bücher und setze den Adapter
        appViewModel.allBooks.observe(viewLifecycleOwner) { books ->
            recyclerView.adapter = BookAdapter(books) { book ->
                // Navigiere zu BookDetailsFragment mit dem Buch als Argument
                val action = LibraryShowBooksFragmentDirections.actionLibraryShowBooksFragmentToBookDetailsFragment(book.bookId)
                findNavController().navigate(action)
            }
        }

        return view
    }

}

Here it doesnt work:

package com.example.travelfriends.ui.fragments

import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.travelfriends.R
import com.example.travelfriends.data.AppViewModel
import com.example.travelfriends.data.QuestionAdapter

class BookDetailsFragment : Fragment() {

    private lateinit var appViewModel: AppViewModel
    private lateinit var imageBook: ImageView
    private lateinit var bookTitle: TextView

    private val args: BookDetailsFragmentArgs by navArgs()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_book_details, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        appViewModel = ViewModelProvider(requireActivity())[AppViewModel::class.java]
        imageBook = view.findViewById(R.id.imageBook)
        bookTitle = view.findViewById(R.id.tvBookDetailsTitle)

        val bookId = args.bookId


        // Buchdaten beobachten und anzeigen
        appViewModel.getBookDetailsById(bookId)

        appViewModel.bookDetails.observe(viewLifecycleOwner) { book ->
            if (isAdded && book != null) {
                bookTitle.text = book.name

                val imageUri = book.image
                Log.d("Glide", "uri: ${imageUri}")
                Log.d("Glide", "context: ${context}")
                if (imageUri.isNotEmpty()) {
                    context?.let {
                        Glide.with(it)
                            .load(imageUri)
                            .placeholder(R.drawable.ic_launcher_foreground)
                            .error(R.drawable.ic_launcher_foreground)
                            .into(imageBook)
                    }
                } else {
                    imageBook.setImageResource(R.drawable.ic_launcher_foreground)
                }
            }


        }
    }
}

Here are the Log-Messages (its the same context and uri)

2025-01-08 23:15:37.489 10919-10919 Glide                   com.example.travelfriends            D  Context available: com.example.travelfriends.ui.MainActivity@5de4605
2025-01-08 23:15:37.489 10919-10919 Glide                   com.example.travelfriends            D  Loading image from URI: content://media/external/images/media/1000000032
2025-01-08 23:15:39.895 10919-10919 Glide                   com.example.travelfriends            D  uri: content://media/external/images/media/1000000032
2025-01-08 23:15:39.896 10919-10919 Glide                   com.example.travelfriends            D  context: com.example.travelfriends.ui.MainActivity@5de4605
2025-01-08 23:15:39.899 10919-10919 ViewTarget              com.example.travelfriends            I  Glide treats LayoutParams.WRAP_CONTENT as a request for an image the size of this device's screen dimensions. If you want to load the original image and are ok with the corresponding memory cost and OOMs (depending on the input size), use override(Target.SIZE_ORIGINAL). Otherwise, use LayoutParams.MATCH_PARENT, set layout_width and layout_height to fixed dimension, or use .override() with fixed dimensions.
2025-01-08 23:15:39.900 10919-10919 ViewTarget              com.example.travelfriends            I  Glide treats LayoutParams.WRAP_CONTENT as a request for an image the size of this device's screen dimensions. If you want to load the original image and are ok with the corresponding memory cost and OOMs (depending on the input size), use override(Target.SIZE_ORIGINAL). Otherwise, use LayoutParams.MATCH_PARENT, set layout_width and layout_height to fixed dimension, or use .override() with fixed dimensions.
2025-01-08 23:15:39.982 10919-10919 Glide                   com.example.travelfriends            W  Load failed for [content://media/external/images/media/1000000032] with dimensions [746x746]
                                                                                                    class com.bumptech.glide.load.engine.GlideException: Failed to load resource
                                                                                                    There was 1 root cause:
                                                                                                    java.lang.SecurityException(com.example.travelfriends has no access to content://media/external/images/media/1000000032)
                                                                                                     call GlideException#logRootCauses(String) for more detail
                                                                                                      Cause (1 of 1): class java.lang.SecurityException: com.example.travelfriends has no access to content://media/external/images/media/1000000032
2025-01-08 23:15:39.983 10919-10956 GlideExecutor           com.example.travelfriends            E  Request threw uncaught throwable
                                                                                                    java.lang.SecurityException: com.example.travelfriends has no access to content://media/external/images/media/1000000032

Would be very glad, if someone can help and fix the issue and can explain, what i did wrong. I didnt find anyone else having this issue in the past :(

Thank you!

Upvotes: 0

Views: 23

Answers (0)

Related Questions