11

I am trying to load an image to a push notification using Glide but it says this:

FATAL EXCEPTION: Thread-9730
Process: com.monkingme.monkingmeapp, PID: 24226
java.lang.IllegalArgumentException: You must call this method on the main thread at com.bumptech.glide.util.Util.assertMainThread(Util.java:135)                                                                                

And the code used:

NotificationTarget notificationTarget = new NotificationTarget(
                context,
                rv,
                R.id.remoteview_notification_icon,
                notification,
                NOTIFICATION_ID);

Glide.with(context.getApplicationContext())
     .load(item.getString("cover_img"))
     .asBitmap()
     .placeholder(placeholder)
     .error(placeholder)
     .into(notificationTarget);

I am using MessageHandler from Aerogear --> https://aerogear.org/docs/guides/aerogear-android/push/

The thing is that in a push notification the app is not running, so there isn't a main thread. Any suggestion?

Zoe
  • 27,060
  • 21
  • 118
  • 148
Damia Fuentes
  • 5,308
  • 6
  • 33
  • 65
  • 1
    that's a great question – Ahmed Ali Dec 02 '18 at 14:04
  • 1
    As of Glide 4.9.0 loading images outside the main thread should work out of the box! https://github.com/bumptech/glide/commit/8f1ea5c07dff7ade8c49c324bcb5a7f40d0b4891 – yuval Feb 20 '19 at 02:25

4 Answers4

8

Try that way:

    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override 
            public void run() {
                 Glide.with(context.getApplicationContext())
                    .load(item.getString("cover_img"))
                    .asBitmap()
                    .placeholder(placeholder)
                    .error(placeholder)
                    .into(notificationTarget);
        }
    });
Divers
  • 9,531
  • 7
  • 45
  • 88
6

This is expected. Since image is loaded from internet, it should always be in a async call or a background thread. You can use a async task or image loading libs like Glide.

To load image notification from a url, you can use the style "NotificationCompat.BigPictureStyle()". This requires a bitmap (which has to be extracted from image url)

Most of the API's and methods of Glide are now deprecated. Below is working with Glide 4.9 and upto Android 10.

 // Load bitmap from image url on background thread and display image notification
        private void getBitmapAsyncAndDoWork(String imageUrl) {

            final Bitmap[] bitmap = {null};

            Glide.with(getApplicationContext())
                    .asBitmap()
                    .load(imageUrl)
                    .into(new CustomTarget<Bitmap>() {
                        @Override
                        public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {

                            bitmap[0] = resource;
                            // TODO Do some work: pass this bitmap
                            displayImageNotification(bitmap[0]);
                        }

                        @Override
                        public void onLoadCleared(@Nullable Drawable placeholder) {
                        }
                    });
        }

Display the image notification once, the bitmap is ready.

private void displayImageNotification(Bitmap bitmap) {

      NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), getChannelId());
            builder
                    .setContentTitle(title)
                    .setContentText(subtext)
                    .setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE)
                    .setSmallIcon(SMALL_ICON)
                    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                    .setColor(getApplicationContext().getColor(color))
                    .setAutoCancel(true)
                    .setOngoing(false)
                    .setOnlyAlertOnce(true)
                    .setContentIntent(pendingIntent)
                     .setStyle(
                     new NotificationCompat.BigPictureStyle().bigPicture(bitmap))
                    .setPriority(Notification.PRIORITY_HIGH);

        getManager().notify(tag, id, builder.build());
}
Mayuri Khinvasara
  • 1,437
  • 1
  • 16
  • 12
  • 1
    This method causes some bugs, whenever the loading image failed. or none of the callbacks are called during thread termination (for example in a broadcast receiver) you should create an approach to handle these cases also. – Amir Hossein Ghasemi Apr 21 '20 at 15:23
1

My solution:

public class NotificationBuilder {

  public static void build(Context context) {
    ...
    NotificationCompat.Builder notificationBuilder =
        new NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.drawable.app_icon_notification).setContentTitle("Title")
            .setContentText("Description").setAutoCancel(true).setShowWhen(true)
            .setWhen(1574521462).setLights(ledColor, 200, 2000)
            .setPriority(NotificationCompat.PRIORITY_MAX)
            .setStyle(new NotificationCompat.BigTextStyle().bigText("Description"))
            .setTicker("Description").setSound(defaultSoundUri).setContentIntent(pendingIntent);
    FutureTarget<Bitmap> futureTarget = GlideApp.with(context).asBitmap()
        .load("http://example.com/myImage.jpg")
        .circleCrop().submit();
    LoadImageTask task = new LoadImageTask(icon -> {
          notificationBuilder.setLargeIcon(icon);
          GlideApp.with(context).clear(futureTarget);
          notificationManager.notify(NotificationsCons.SUPPORT_MESSAGES_NOTIFICATION_ID,
              notificationBuilder.build());
        });
    task.execute(futureTarget);
  }
}

private static class LoadImageTask extends AsyncTask<FutureTarget<Bitmap>, Void, Bitmap> {
  private OnSuccess onSuccess;

  interface OnSuccess {
    void onSuccess(Bitmap bitmap);
  }

  LoadImageTask(OnSuccess onSuccess) {
    this.onSuccess = onSuccess;
  }

  @SafeVarargs @Override
  protected final Bitmap doInBackground(FutureTarget<Bitmap>... futureTargets) {
    try {
      return futureTargets[0].get();
    } catch (ExecutionException e) {
      e.printStackTrace();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return null;
  }

  @Override protected void onPostExecute(Bitmap bitmap) {
    super.onPostExecute(bitmap);
    if (bitmap != null)
      onSuccess.onSuccess(bitmap);
  }
}

It works fine.

DrMorteza
  • 2,067
  • 2
  • 21
  • 29
1

For those who might be confused with the latest version of Glide and in Kotlin:

val target = NotificationTarget(
            context,
            R.id.iv_image,
            remoteView,
            notification,
            NOTIFICATION_ID)

Glide.with(context.applicationContext)
        .asBitmap()
        .load(url)
        .into(target)

It's important to note that asBitmap() should come right after with(context)

Rachit
  • 3,173
  • 3
  • 28
  • 45