Load image from url in notification Android

AndroidBitmapGoogle Cloud-MessagingAndroid NotificationsAndroid Notification-Bar

Android Problem Overview


In my android application, i want to set Notification icons dynamically which will be loaded from URL. For that, i have used setLargeIcon property of NotificationBuilder in receiver.I reffered many link and tried various solutions but couldn't get desired output. Though i downloaded that image from url and setting that bitmap in notification, it is not being displayed. Instead it displays the setSmallIcon image as large icon. I don't know where i am going wrong. Here i am posting my code. Please help me to solve this issue. Thank you.

Code:

@SuppressLint("NewApi")
public class C2DMMessageReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		String action = intent.getAction();
		if ("com.google.android.c2dm.intent.RECEIVE".equals(action)) {
			Log.e("C2DM", "received message");
			final String fullName = intent.getStringExtra("message");
			final String payload1 = intent.getStringExtra("message1");
			final String payload2 = intent.getStringExtra("message2");
			final String userImage = intent.getStringExtra("userImage");
			
			Log.e("userImage Url :", userImage); //it shows correct url

			new sendNotification(context)
					.execute(fullName, payload1, userImage);
		}
	}

private class sendNotification extends AsyncTask<String, Void, Bitmap> {

		Context ctx;
		String message;

		public sendNotification(Context context) {
			super();
			this.ctx = context;
		}

		@Override
		protected Bitmap doInBackground(String... params) {

			InputStream in;
			message = params[0] + params[1];
			try {

				in = new URL(params[2]).openStream();
				Bitmap bmp = BitmapFactory.decodeStream(in);
				return bmp;

			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}

		@Override
		protected void onPostExecute(Bitmap result) {

			super.onPostExecute(result);
			try {
				NotificationManager notificationManager = (NotificationManager) ctx
						.getSystemService(Context.NOTIFICATION_SERVICE);
				
				Intent intent = new Intent(ctx, NotificationsActivity.class);
				intent.putExtra("isFromBadge", false);
				

				Notification notification = new Notification.Builder(ctx)
						.setContentTitle(
								ctx.getResources().getString(R.string.app_name))
						.setContentText(message)
						.setSmallIcon(R.drawable.ic_launcher)
						.setLargeIcon(result).build();

				// hide the notification after its selected
				notification.flags |= Notification.FLAG_AUTO_CANCEL;

				notificationManager.notify(1, notification);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

Android Solutions


Solution 1 - Android

Changed my code as below and its working now :

private class sendNotification extends AsyncTask<String, Void, Bitmap> {

        Context ctx;
        String message;

        public sendNotification(Context context) {
            super();
            this.ctx = context;
        }

        @Override
        protected Bitmap doInBackground(String... params) {

            InputStream in;
            message = params[0] + params[1];
            try {

                  URL url = new URL(params[2]);
                  HttpURLConnection connection = (HttpURLConnection)url.openConnection();
                  connection.setDoInput(true);
                  connection.connect();
                  in = connection.getInputStream();
                  Bitmap myBitmap = BitmapFactory.decodeStream(in);
                  return myBitmap;
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap result) {

            super.onPostExecute(result);
            try {
                NotificationManager notificationManager = (NotificationManager) ctx
                        .getSystemService(Context.NOTIFICATION_SERVICE);

                Intent intent = new Intent(ctx, NotificationsActivity.class);
                intent.putExtra("isFromBadge", false);


                Notification notification = new Notification.Builder(ctx)
                        .setContentTitle(
                                ctx.getResources().getString(R.string.app_name))
                        .setContentText(message)
                        .setSmallIcon(R.drawable.ic_launcher)
                        .setLargeIcon(result).build();

                // hide the notification after its selected
                notification.flags |= Notification.FLAG_AUTO_CANCEL;

                notificationManager.notify(1, notification);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

Solution 2 - Android

How to implement BigPicture style Notification:

Miracle has been done by .setStyle(new Notification.BigPictureStyle().bigPicture(result)) :

I have done this way with:

enter image description here

Generate notification by AsyncTask:

new generatePictureStyleNotification(this,"Title", "Message", 
                 "http://api.androidhive.info/images/sample.jpg").execute();

AsyncTask:

public class generatePictureStyleNotification extends AsyncTask<String, Void, Bitmap> {

        private Context mContext;
        private String title, message, imageUrl;

        public generatePictureStyleNotification(Context context, String title, String message, String imageUrl) {
            super();
            this.mContext = context;
            this.title = title;
            this.message = message;
            this.imageUrl = imageUrl;
        }

        @Override
        protected Bitmap doInBackground(String... params) {

            InputStream in;
            try {
                URL url = new URL(this.imageUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setDoInput(true);
                connection.connect();
                in = connection.getInputStream();
                Bitmap myBitmap = BitmapFactory.decodeStream(in);
                return myBitmap;
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        @Override
        protected void onPostExecute(Bitmap result) {
            super.onPostExecute(result);

            Intent intent = new Intent(mContext, MyOpenableActivity.class);
            intent.putExtra("key", "value");
            PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 100, intent, PendingIntent.FLAG_ONE_SHOT);

            NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
            Notification notif = new Notification.Builder(mContext)
                    .setContentIntent(pendingIntent)
                    .setContentTitle(title)
                    .setContentText(message)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(result)
                    .setStyle(new Notification.BigPictureStyle().bigPicture(result))
                    .build();
            notif.flags |= Notification.FLAG_AUTO_CANCEL;
            notificationManager.notify(1, notif);
        }
    }

Solution 3 - Android

you can do this using Glide like this:

val notificationBuilder = NotificationCompat.Builder(this, channelId)
        .setSmallIcon(R.drawable.ic_message)
        .setContentTitle("title")
        .setContentText("text")

val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

val futureTarget = Glide.with(this)
        .asBitmap()
        .load(photoUrl)
        .submit()

val bitmap = futureTarget.get()
notificationBuilder.setLargeIcon(bitmap)

Glide.with(this).clear(futureTarget)

notificationManager.notify(0, notificationBuilder.build())

preview

Solution 4 - Android

Top answer in Kotlin and with Coroutines. This method applies the bitmap to the builder instead of a direct assignment, and of course if bitmap available. It's nice because if the url is wrong it will be caught in the try/catch.

fun applyImageUrl(
    builder: NotificationCompat.Builder, 
    imageUrl: String
) = runBlocking {
    val url = URL(imageUrl)

    withContext(Dispatchers.IO) {
        try {
            val input = url.openStream()
            BitmapFactory.decodeStream(input)
        } catch (e: IOException) {
            null
        }
    }?.let { bitmap ->
        builder.setLargeIcon(bitmap)
    }
}

with Kotlin & RxJava

fun applyImageUrl(
    builder: NotificationCompat.Builder,
    imageUrl: String
) {
    val url = URL(imageUrl)

    Single.create<Bitmap> { emitter ->
        try {
            val input = url.openStream()
            val bitmap = BitmapFactory.decodeStream(input)
            emitter.onSuccess(bitmap)
        } catch (e: Exception) {
            emitter.onError(e)
        }
    }.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
            {
                builder.setLargeIcon(it)
            }, {
                Timber.e("error generating bitmap for notification")
            }
        )
}

Solution 5 - Android

Since image is loaded from internet, it should be done async in a background thread. Either use async task or Glide (for efficient image loading).

To load image notification, you need to use "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());
}

Solution 6 - Android

I know a good answer has been given so let's see if we can make it easier to understand and implement.
---------------------Theory------------------------
The problem can be abstracted in two step solution namely

  1. Get image from a URL

  2. Decode image and pass to notification builder

  3. Get image from a URL
    InputStream in = new URL("Img URL goes here eg. http://gg.com/profile.jpg").openStream();

  4. Decode and pass to notification
    Bitmap bmp = null; #create a null bmp container that will be used to hold decoded img
    bmp = BitmapFactory.decodeStream(in); # save the image into container

Voila! once you build the image and save it in the variable bmp, you can call it on notification builder .setLargeIcon(bmp)

--------Implementation---------------
Android studio will encourage you to wrap your code with try catch so the end product will look like this.

Bitmap bmp = null;
try {
    InputStream in = new URL("url goes here").openStream();
    bmp = BitmapFactory.decodeStream(in);
} catch (IOException e) {
    e.printStackTrace();
}

Once you have the bmp you can call it in notification builder as

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher)
            .setContentText("title")
            .setContentText("text goes here")
            .setLargeIcon(bmp)
            .setAutoCancel(true);

Solution 7 - Android

Using Picasso Library.

               Target target = new Target() {
                    @Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        largeIcon=bitmap;
                    }

                    @Override
                    public void onBitmapFailed(Drawable errorDrawable) {
                    }

                    @Override
                    public void onPrepareLoad(Drawable placeHolderDrawable) {
                    }
                };

                Picasso.with(this).load("url").into(target); 





               NotificationCompat.Builder notificationBuilder =
                    new NotificationCompat.Builder(this, channelId)
                            .setSmallIcon(R.drawable.icon)
                            .setContentTitle(msg.getString("title"))
                            .setContentText(msg.getString("msg"))
                            .setAutoCancel(true)
                            .setSound(defaultSoundUri)
                            .setLargeIcon(largeIcon)
                            .setContentIntent(pendingIntent);

Solution 8 - Android

Since I couldn't find any working solution for Picasso I'm posting my complete and working(July 2020) example using Picasso below.

It is sending the notification immediately and then updates it when the image for setLargeIcon() has been loaded. Normally this is very quick and the user should only see the updated version of the notification in most cases.

private void sendNotification(String message, String title, final String photoUrl) {
    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
            PendingIntent.FLAG_ONE_SHOT);

    final NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.wbib_transp_512)
                    .setContentTitle(title)
                    .setContentText(message)
                    .setAutoCancel(true)
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setCategory(NotificationCompat.CATEGORY_MESSAGE)
                    .setContentIntent(pendingIntent);

    final NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0, notificationBuilder.build());

    final Handler uiHandler = new Handler(Looper.getMainLooper());
    uiHandler.post(new Runnable() {
        @Override
        public void run() {
            Picasso.get()
                    .load(photoUrl)
                    .resize(200, 200)
                    .into(new Target() {
                        @Override
                        public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) {
                            notificationBuilder.setLargeIcon(bitmap);
                            notificationManager.notify(0, notificationBuilder.build());
                        }

                        @Override
                        public void onBitmapFailed(Exception e, final Drawable errorDrawable) {
                            // Do nothing?
                        }

                        @Override
                        public void onPrepareLoad(final Drawable placeHolderDrawable) {
                            // Do nothing?
                        }
                    });
        }
    });


}

Solution 9 - Android

RxJava and Picasso way

private fun bigImageNotification(ctx: Context, title: String, msg: String, imgUrl: String): Disposable? {
    return Observable.fromCallable {
        Picasso.get().load(imgUrl).get()
    }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({
                createNotification(ctx, title, msg, it)
            }, {it.printStackTrace()})
}

private fun createNotification(ctx: Context, title: String, msg: String, img: Bitmap?) {
    val b = Notification.Builder(ctx)
    b.setAutoCancel(true)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setContentText(msg)
            .setStyle(Notification.BigPictureStyle().bigPicture(img))
    val notificationManager = ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.notify(1000, b.build())
}

Usage

bigImageNotification(context, "title", "msg", "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZankhnaView Question on Stackoverflow
Solution 1 - AndroidZankhnaView Answer on Stackoverflow
Solution 2 - AndroidHiren PatelView Answer on Stackoverflow
Solution 3 - AndroidDan AlboteanuView Answer on Stackoverflow
Solution 4 - AndroidJuan MendezView Answer on Stackoverflow
Solution 5 - AndroidMayuri KhinvasaraView Answer on Stackoverflow
Solution 6 - Androiduser10475447View Answer on Stackoverflow
Solution 7 - AndroidSunil SoniView Answer on Stackoverflow
Solution 8 - AndroidJohn TView Answer on Stackoverflow
Solution 9 - AndroidRadeshView Answer on Stackoverflow