ChatKit
ChatKit copied to clipboard
Setting image by byte stream array
How do I set image message by byte stream array instead of image url? I can't seem to find an example that does that. Please help.
@pingpingsim https://github.com/stfalcon-studio/ChatKit/blob/master/docs/IMAGE_LOADER.md It looks like you can override it and use something called Picasso to load a byte stream array instead of the url. This could help: https://stackoverflow.com/questions/34629424/how-to-load-bitmap-directly-with-picasso-library-like-following or https://stackoverflow.com/questions/33959599/android-load-byte-into-imageview-with-picasso
COULD is the keyword. Haven't developed Android in awhile (getting back to it). There's probably another way of loading your byte stream into the image view though.
I think override and loading the image with Picasso or Glide is the way to go.
The given ImageMessageViewHolder's onBind method expect to retrieve a url from the message to be used in loadImage
https://github.com/stfalcon-studio/ChatKit/blob/master/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListAdapter.java
Then at the ImageLoader you are given only the url
https://github.com/stfalcon-studio/ChatKit/blob/master/chatkit/src/main/java/com/stfalcon/chatkit/commons/ImageLoader.java
Furthermore, this library check if a message has null url to determine if it is a image type
This library does not consider the use case of loading image other than using url
@pingpingsim
Instead of using the given class in the library, create your own class that extend from the library class
Create your own ImageLoader class that implement ImageLoader,
for example
public class UidlImageLoader implements ImageLoader {
Context context;
public UidlImageLoader(Context context){
this.context = context;
}
public void loadImage(ImageView imageView, byte[] data, @Nullable Object payload) {
Glide.with(context)
.asBitmap()
.load(data)
.into(imageView);
}
Create your own ImageMessage class
public class ImageMessage implements IMessage,
MessageContentType.Image {
private final Author author;
private final byte[] imageData;
private final Date createdTime;
public ImageMessage(Author author, byte[] imageData, Date createdTime){
this.author = author;
this.imageData= imageData;
this.createdTime = createdTime;
}
Here is the tricky part, create your own CustomOutcomingImageMessageViewHolder and override its onBind method,
it will get the byte data from your own ImageMessage class, and use your own ImageLoader to do the loading
/**
* Default view holder implementation for outcoming image message
*/
public static class CustomOutcomingImageMessageViewHolder<MESSAGE extends MessageContentType.Image>
extends CustomBaseOutcomingMessageViewHolder<MESSAGE> {
protected ImageView imageView;
protected View imageOverlay;
public CustomOutcomingImageMessageViewHolder(View itemView, Object payload, CustomMessagesListStyle style) {
super(itemView, payload, style);
init(itemView);
}
@Override
public void onBind(MESSAGE message) {
super.onBind(message);
if (imageView != null && imageLoader instanceof UidlImageLoader
&& message instanceof ImageMessage) {
ImageMessage imageMessage = (ImageMessage)message;
byte[] imageData = imageMessage.getImageByte();
UidlImageLoader uidlImageLoader = (UidlImageLoader)imageLoader;
uidlImageLoader.loadImage(imageView, imageData , getPayloadForImageLoader(message));
}
if (imageOverlay != null) {
imageOverlay.setSelected(isSelected());
}
}
You need to make a wrapper class because the generic constraint
public static class UidlOutComingImageVH extends CustomOutcomingImageMessageViewHolder<MessageContentType.Image> {
public UidlOutComingImageVH(View itemView) {
super(itemView, null, style);
}
}
finally tell the library to use your own class for ImageHolder
// set the layout of the incoming dialogue bubbles
MessageHolders messageHolders = new MessageHolders();
messageHolders.setOutcomingImageHolder(UidlOutComingImageVH.class);
Just override getPayloadForImageLoader in custom VH and implement own logic in ImageLoader, in your case replace string with byte stream array and customize logic in ImageLoader.
class CustomOutcomingImageMessageViewHolder(private val itemView: View, payload: Any?) :
MessageHolders.IncomingImageMessageViewHolder<Message>(itemView, payload) {
override fun onBind(message: Message) {
super.onBind(message)
time?.text = "${DateFormatter.format(message.createdAt, DateFormatter.Template.TIME)} Status"
}
override fun getPayloadForImageLoader(message: Message?): Any? {
return message?.image?.localImagePath
}
}
// Create image loader for adapter
this.imageLoader = ImageLoader { imageView: ImageView, url: String?, payload: Any? ->
if (url.isNullOrEmpty()) {
imageView.load(File(payload as (String)))
} else {
imageView.load(url)
}
}