In the Coil image library I am trying to get when the image has been successfully loaded and then use Palette to get the colors from the bitmap but I am having a problem where if I use the ImageRequests's target the image does not show in the imageview but the onSuccess completes correctly because I am able to extract the color from the given bitmap
Here is what I have
_contentImage.load(File(image))
{
crossfade(true)
allowHardware(false)
listener(onError = { _, error ->
Log.d(SUBTAG, "Error -> ${error.message}")
},
onSuccess = {_, _ ->
Log.d(SUBTAG, "Content image loaded")
contentImageLoaded = true
checkContentLoaded()
})
target(
onSuccess = { result ->
Palette.from(result.toBitmap()).generate {
if (it != null) {
val paletteColor = it.getDominantColor(color)
_constraintLayout.setBackgroundColor(paletteColor)
}
}
}
)
}
If I comment out the whole target section of the builder the image shows fine but obviously I don't get the palette stuff
Do I have to manually set the drawable to the image if I use the onSuccess like this
target(
onSuccess = { result ->
Palette.from(result.toBitmap()).generate {
if (it != null) {
val paletteColor = it.getDominantColor(color)
_constraintLayout.setBackgroundColor(paletteColor)
}
}
_contentImage.setImageDrawable(result) // Set it here?
}
)
If I do that the image shows but it seems odd to have to manually set it and I feel like it should be set by itself
Not sure what the problem is here
Related
I'm trying to make a WearOS Complication that is just an image. Ideally, it should display the image img1.png when on like this, and the image outlines.png when in ambient mode like this.
Right now, I've got
return when (request.complicationType) {
ComplicationType.SMALL_IMAGE -> SmallImageComplicationData.Builder(
smallImage = SmallImage.Builder(
Icon.createWithResource(this, R.drawable.img1), SmallImageType.PHOTO).build(),
contentDescription = PlainComplicationText
.Builder(text = "Sample text").build()
)
.setTapAction(complicationPendingIntent)
.build()
else -> {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unexpected complication type ${request.complicationType}")
}
null
}
}
and I want to add the ambient image somewhere but don't know how. This code sample is inside the onComplicationRequest function, which returns ComplicationData? by the way. I have the same issue with
override fun getPreviewData(type: ComplicationType): ComplicationData {
return SmallImageComplicationData.Builder(
smallImage = SmallImage.Builder(
Icon.createWithResource(this, R.drawable.img1), SmallImageType.PHOTO).build(),
contentDescription = PlainComplicationText
.Builder(text = "Your loved one's images!").build()
)
.setTapAction(null)
.build()
}
which again, returns ComplicationData. Any ideas? Thanks!
(The documentation for WearOS development is pretty incomplete imo :P)
It's on SmallImage.Builder
https://developer.android.com/reference/androidx/wear/watchface/complications/data/SmallImage.Builder#setAmbientImage(android.graphics.drawable.Icon)
Try
SmallImageComplicationData.Builder(
smallImage = SmallImage.Builder(
Icon.createWithResource(this, R.drawable.img1), SmallImageType.PHOTO)
.setAmbientImage(...)
.build(),
contentDescription = PlainComplicationText
.Builder(text = "Sample text").build()
)
.setTapAction(complicationPendingIntent)
.build()
I take uri from db and would like to show an image:
val uri by viewModel.uri.collectAsState()
Image(
painter = rememberAsyncImagePainter(
ImageRequest
.Builder(LocalContext.current)
.data(data = uri)
.build()
),
contentDescription = ""
)
but it is not loading - it is blank.
When debugging I can see that on recomposition
Image->Uri->uriString is set to correct value - "content://com.android.providers.media.documents/document/image%3A44"
but itis still not visible.
It is only visible if I pick it again using:
val pickMedia =
rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri != null) {
viewModel.onImageSelected(uri)
} else {
Log.d("PhotoPicker", "No media selected")
}
}
I am reusing the same image in many places and from now on it is visible everywhere (but still no other image is visible until I repick it again).
After closing and reopening app images are not visible again.
Maybe it is some caching? or permissions?
The toolbar for accepting, canceling, or rotating the image does not
appear. I use the Android-Image-Cropper library, https://github.gitop.top/CanHub/Android-Image-Cropper. I'm still a
beginner and so far I don't understand why I can't do it.
private val cropImage = registerForActivityResult(CropImageContract()) { result ->
if (result.isSuccessful) {
// use the returned uri
val uriContent = result.uriContent
val path = REF_STORAGE_ROOT.child(FOLDER_PROFILE_IMAGE)
.child(CURRENT_UID)
uriContent?.let { path.putFile(it).addOnCompleteListener {
if (it.isSuccessful) {
showToast(getString(R.string.toast_data_update))
}
} }
private fun startCrop() {
cropImage.launch(
options() {
setGuidelines(CropImageView.Guidelines.ON)
setAspectRatio(1, 1)
setRequestedSize(600, 600)
setCropShape(CropImageView.CropShape.OVAL)
}
)
}
What I have now:
As I would like it to be:
Does your app theme has no action bar? If yes, you should add this to your manifest. I added this and it helped me
<activity android:name="com.canhub.cropper.CropImageActivity"
android:theme="#style/Base.Theme.AppCompat"/>
(Edited Question....)
I am developing a chat application and there is a specific API so some things i must implement them with a specific way. For example (and the case that i have a problem...)
When i have to display an Image the API says that i have to split the Image in small chunks and store them as a message with a byteArray content. There is also a header message that its body is the messageIds of the fileChunks. So in the RecyclerView inside the onBindViewHolder, when i see a header file message (msgType == 1) then i start a coroutine to fetch the chunkFile messages by the ids, construct the File and then switch to the MainDispatcher, and so the Image with Glide using a BitmapFactory.decodeByteArray. The code is shown below
messageItem.message?.msgType == MSG_TYPE_FILE -> {
holder.sntBody.text = "Loading file"
val fileInfo = Gson().fromJson(URLDecoder.decode(messageItem.message?.body, "UTF-8"), FileInformation::class.java)
job = chatRoomAdapterScope.launch(Dispatchers.IO) {
// i get the messageIds of the chunks from Header message
val segSequence = fileInfo.seg.split(",").map { it.toLong() }
// i get the fileChunks from Database
val fileChunks = AppDatabase.invoke(mContext).messageDao().getMessageById(segSequence)
val compactFile = ByteArrayOutputStream()
// Reconstruct the file
for (chunk in fileChunks)
compactFile.write(Base64.decode(chunk.fileBody, Base64.DEFAULT))
withContext(Dispatchers.Main) {
val bitmapOptions = BitmapFactory.Options().apply {
inSampleSize = 8
}
Glide.with(mContext).asBitmap()
.load(BitmapFactory.decodeByteArray(compactFile.toByteArray(), 0, compactFile.size(), bitmapOptions)!!)
.fitCenter()
.into(object : SimpleTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
holder.sntImageView.setImageBitmap(resource)
holder.sntImageView.visibility = View.VISIBLE
}
})
holder.sntBody.text = fileInfo.filename
}
}
}
My problem is that when i scroll fast the image that is supposed to be loaded in an item appears in another item. My first guess is that the Coroutine that started from a specific item didnt complete as soon as the item was recycled so when the coroutine finished it had a reference to a new item, so i added the
holder.itemView.addOnAttachStateChangeListener method as some people commented. However i didn't work.
Is there any idea of why that may happens and if there is a better implementation of the proccess according to the specific API...?
I think that you can use View.OnAttachStateChangeListener for it:
override fun onBindViewHolder() {
if(messageType == TYPE_FILE) {
val job = chatRoomAdapterScope.launch(Dispatchers.IO) {
val fileChunks = AppDatabase.invoke(MyApplication.instance).messageDao()
.getMessageByMessageId(segSequence)
// do some heacy work with the fileChunks
withContext(Dispatchers.Main) {
// holder set up
}
}
holder.itemView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewDetachedFromWindow(view: View) {
view.removeOnAttachStateChangeListener(this)
job.cancel()
}
override fun onViewAttachedToWindow(p0: View?) {}
})
}
}
Currently, I have an app that uses Picasso to download images and display them in a recyclerview.
I want to change my logic by totally doing away with Picasso and downloading images in the background when the app is initially installed. During succeeding runs of the app, the images will be displayed from internal storage.
So, how would I let the recyclerview know that the image is ready for display after it has been successfully saved in internal storage? I'd prefer if they aren't shown all at once because that would take too long, but show each image as the download is completed (kind of similar to how Picasso does it).
This is my current onBindViewHolder code:
override fun onBindViewHolder(rawHolder: RecyclerView.ViewHolder, position: Int) {
val holder = rawHolder as CustomVH
holder.resourcesByCategory = resourcesByCategory[position]
val dir : String = utils.getInternalDirectory("Covers") + "/CoverBookId" + resourcesByCategory[position].id + ".jpg"
val bookCover = File(dir)
if (bookCover.exists()) {
if (holder.bmp != null) {
holder.bmp!!.recycle()
}
holder.resourceCover.setImageBitmap(null)
val options = BitmapFactory.Options()
options.inPreferredConfig = Bitmap.Config.RGB_565
holder.bmp = BitmapFactory.decodeStream(FileInputStream(bookCover), null, options)
if (holder.bmp != null) {
holder.bmp = Bitmap.createScaledBitmap(holder.bmp, 150,180, true)
holder.resourceCover.setImageBitmap(holder.bmp!!)
}
}
}