App keeps crashing when i try to load image

Viewed 49

Please i have been trying this for weeks now. I have a fragment that displays notifications. But it time i click on the notification my app crashes. it points me the line below Picasso.get().load(user!!.getImage()).placeholder(R.drawable.profile).into(imageView)

and it says: java.lang.IllegalArgumentException: Path must not be empty

From logcat, using picasso seems to be the problem but i am new to programming and i have no idea what exacty to do. Please help me. Thank you

Below is the complete code for my notificationAdapter

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

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val notification = mNotification[position]

    if(notification.getText().equals("Admirers you")){
        holder.text.text = "Admirers you"
    }
    else if(notification.getText().equals("Liked your post")){
        holder.text.text = "Liked your post"
    }
    else if (notification.getText().contains("commented:")){
        holder.text.text = notification.getText().replace("commented:", "commented: ")
    }
    else{
        holder.text.text = notification.getText()
    }



    userInfo(holder.profileImage, holder.fullname, notification.getUserId())

    if(notification.isIsPost()){
        holder.postImage.visibility = View.VISIBLE
        getPostImage(holder.postImage, notification.getPostId())
    }
    else{
        holder.postImage.visibility = View.GONE
    }

    holder.itemView.setOnClickListener {
            if(notification.isIsPost()){
                val editor = mContext.getSharedPreferences("PREFS", Context.MODE_PRIVATE).edit()

                editor.putString("postId", notification.getPostId())

                editor.apply()
                (mContext as FragmentActivity).getSupportFragmentManager()
                    .beginTransaction()
                    .replace(R.id.fragment_container, PostDetailsFragment()).commit()

            }
        else{
                val editor = mContext.getSharedPreferences("PREFS", Context.MODE_PRIVATE).edit()

                editor.putString("profileId", notification.getUserId())

                editor.apply()
                (mContext as FragmentActivity).getSupportFragmentManager()
                    .beginTransaction()
                    .replace(R.id.fragment_container, ProfileFragment()).commit()
            }

        }
}

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


inner class ViewHolder(@NonNull itemView: View) : RecyclerView.ViewHolder(itemView)
{
    var postImage: ImageView
    var profileImage : CircleImageView
    var fullname : TextView
    var text : TextView

    init {
        postImage = itemView.findViewById(R.id.notification_post_image)
        profileImage = itemView.findViewById(R.id.notifications_profile_image)
        fullname = itemView.findViewById(R.id.fullname_notification)
        text = itemView.findViewById(R.id.comment_notification)
    }
}

private fun userInfo(imageView: ImageView, fullname: TextView, publisherId:String)
{
    val usersRef =
        FirebaseDatabase.getInstance().reference
            .child("Users")
            .child(publisherId)



    usersRef.addValueEventListener(object : ValueEventListener
    {
        override fun onDataChange(p0: DataSnapshot)
        {
            if (p0.exists())
            {
                val user = p0.getValue(User::class.java)


                Picasso.get().load(user!!.getImage()).placeholder(R.drawable.profile).into(imageView)
                fullname.text = user.getfullname()

            }
        }

        override fun onCancelled(p0: DatabaseError) {

        }
    })
}

private fun getPostImage(imageView: ImageView, postID:String)
{
    val postRef =
        FirebaseDatabase.getInstance()
            .reference.child("Posts")
            .child(postID)

    postRef.addValueEventListener(object : ValueEventListener
    {
        override fun onDataChange(p0: DataSnapshot)
        {
            if (p0.exists()) {
                val post = p0.getValue<Post>(Post::class.java)

                Picasso.get().load(post!!.getpostimage()).placeholder(R.drawable.profile)
                    .into(imageView)

            }
        }

        override fun onCancelled(p0: DatabaseError) {

        }
    })
}

}

And also my notification fragment

    <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="Fragments.NotificationsFragment">

<com.google.android.material.appbar.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/app_bar_layout_notifications"
    android:background="@color/white">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/notifications_toolbar"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginTop="4dp"
        android:layout_marginLeft="6dp"
        android:layout_marginRight="6dp"
        android:background="@android:color/white">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Notifications"
                android:textSize="18sp"
                android:maxLines="1"
                android:textStyle="bold"
                android:textColor="@android:color/black"
                android:layout_centerVertical="true"/>
        </RelativeLayout>
    </androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view_notifications"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="5dp"
    android:layout_below="@+id/app_bar_layout_notifications">

</androidx.recyclerview.widget.RecyclerView>

Then in case you need more info, here's my notifications item layout. Thank you

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="6dp">

<de.hdodenhof.circleimageview.CircleImageView
    android:id="@+id/notifications_profile_image"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:src="@drawable/profile">
</de.hdodenhof.circleimageview.CircleImageView>

<LinearLayout
    android:layout_toEndOf="@+id/notifications_profile_image"
    android:layout_toStartOf="@+id/notification_post_image"
    android:layout_centerVertical="true"
    android:layout_marginStart="5dp"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/fullname_notification"
        android:textStyle="bold"
        android:textColor="@color/teal_200"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </TextView>
    <TextView
        android:id="@+id/comment_notification"
        android:textStyle="bold"
        android:textColor="@color/teal_200"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </TextView>
</LinearLayout>
<ImageView
    android:id="@+id/notification_post_image"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:layout_alignParentEnd="true">
</ImageView>
1 Answers

I don't know Picasso, so I can't tell you what the problem is*. (I don't even know Android, which I guess this is for.) But since you're new to programming, it seems to me that what you need to know is how to find out the problem for yourself — how to debug — so here are some hints that I hope will help.

You've done the right thing in starting with the logs; if you have an exception with a stack trace, that's always helpful in narrowing down the problem. But your case hasn't narrowed it down enough, because that one line is doing many different things. So the simplest thing to try would be to split that line up — then the stack trace's line number will narrow it down more finely.

You could simply wrap the line, e.g.:

Picasso.get()
    .load(user!!.getImage())
    .placeholder(R.drawable.profile)
    .into(imageView)

Then you'll be able to tell which of those main operations triggered the exception. (Of course, the operation that gave the exception might not be the one you need to change — but either way you need to understand the problem before you can fix it.)

If that's not enough, then there are several approaches you could take. But the one I usually end up falling back on is the most general: logging. Whether you're working on a desktop app, a mobile app, a web app, a microservice, a stand-alone app, or whatever, there's almost always a way to print out some text in such a way that you can see it on screen or in a file. As I said, I don't know Android, but this question seems to show how you can do that; in other environments, you might use one of several logging libraries (java.util.logging, log4j…), or just the basic println(). But however you do it, there's bound to be a way you can see some of the intermediate values — and being able to see what's going on is always valuable when debugging.

You could try printing out the user (or, if that doesn't have a simple string representation, their name or something else that might give you a clue). Then the image, ditto. The the results of the load() call. And so on. Of course, that means restructuring your code a bit, e.g.:

val picasso = Picasso.get()
println("picasso = $picasso")

println("user = $user")
val image = user!!.getImage()
println("image = $image")
val loaded = picasso.load(image)
println("loaded = $loaded")

println("profile = ${R.drawable.profile}")
val placeholder = loaded.placeholder(R.drawable.profile)
println("placeholder = $placeholder")

println("imageView = $imageView")
placeholder.into(imageView)

(Substituting whatever logging method works in your case. I'm overdoing it here, of course. But I hope you get the idea.)

For the record, Kotlin's also() gives a way of doing the above without having to name all the temporary variables, or split up the chain of calls:

Picasso.get()
        .also{ println("picasso = $it") }
        .also{ println("user = $user") }
    .load(user!!.getImage().also{ println("image = $it") } )
        .also{ println("loaded = $it") }
    .placeholder(R.drawable.profile.also{ println("profile = $it") })
        .also{ println("placeholder = $it") }
    .into(imageView.also{ println("imageView = $it") })

However, that can get unwieldy pretty quickly, so I wouldn't normally recommend it.

Either way, in all likelihood one of the values you print out won't be what you expect, or you'll be able to spot something that doesn't look right, and that will give you enough info to identify the problem — or at least, to direct your attention to some other part of the code that you can then debug in the same way.

Once you've fixed the problem and the code is behaving as expected, you can remove the logging. However, it's often better to leave some logging code in. (Especially if you're using a logging library that lets you set different levels, so you can log this at a low level that you won't normally get to see.) Then, when you need to track down some other problem in the code, it's much easier to see what's going on.


(* From the exception message, I'd suspect an issue with the user!!.getImage() part. But that's just a blind guess.)

Related