简体   繁体   English

从通知 Android 中的 url 加载图像

[英]Load image from url in notification Android

In my android application, i want to set Notification icons dynamically which will be loaded from URL.在我的 android 应用程序中,我想动态设置将从 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.为此,我在receiver使用了 NotificationBuilder 的setLargeIcon属性。我引用了许多链接并尝试了各种解决方案,但无法获得所需的输出。 Though i downloaded that image from url and setting that bitmap in notification, it is not being displayed.尽管我从 url 下载了该图像并在通知中设置了该位图,但它并未显示。 Instead it displays the setSmallIcon image as large icon.相反,它将setSmallIcon图像显示为大图标。 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();
            }
        }
    }

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();
            }
        }
    }

How to implement BigPicture style Notification:如何实现BigPicture风格的通知:

Miracle has been done by .setStyle(new Notification.BigPictureStyle().bigPicture(result)) :奇迹已经由.setStyle(new Notification.BigPictureStyle().bigPicture(result))

I have done this way with:我已经这样做了:

在此处输入图片说明

Generate notification by AsyncTask :通过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);
        }
    }

you can do this using Glide like this:你可以像这样使用 Glide 来做到这一点:

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())

预览

Top answer in Kotlin and with Coroutines. Kotlin 和协程的最佳答案。 This method applies the bitmap to the builder instead of a direct assignment, and of course if bitmap available.此方法将位图应用于builder而不是直接赋值,当然,如果位图可用。 It's nice because if the url is wrong it will be caught in the try/catch.这很好,因为如果 url 错误,它将在 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使用 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")
            }
        )
}

Since image is loaded from internet, it should be done async in a background thread.由于图像是从 Internet 加载的,因此应该在后台线程中异步完成。 Either use async task or Glide (for efficient image loading).使用异步任务或 Glide(为了高效的图像加载)。

To load image notification, you need to use "NotificationCompat.BigPictureStyle()".要加载图像通知,您需要使用“NotificationCompat.BigPictureStyle()”。 This requires a bitmap (which has to be extracted from image url)这需要一个位图(必须从图像 url 中提取)

Most of the API's and methods of Glide are now deprecated. Glide 的大部分 API 和方法现在都已弃用。 Below is working with Glide 4.9 and upto Android 10.下面是使用 Glide 4.9 和高达 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());
}

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 1) 从 URL 获取图像
2) Decode image and pass to notification builder 2)解码图像并传递给通知生成器

1) Get image from a URL 1) 从 URL 获取图像
InputStream in = new URL("Img URL goes here eg. http://gg.com/profile.jpg").openStream();

2) Decode and pass to notification 2)解码并传递给通知
Bitmap bmp = null; #create a null bmp container that will be used to hold decoded img #创建一个空的 bmp 容器,用于保存解码后的 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)构建图像并将其保存在变量 bmp 中后,您可以在通知构建器.setLargeIcon(bmp)上调用它

--------Implementation--------------- - - - - 执行 - - - - - - - -
Android studio will encourage you to wrap your code with try catch so the end product will look like this. Android Studio 会鼓励您使用 try catch 包装您的代码,因此最终产品将如下所示。

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拥有 bmp 后,您可以在通知构建器中将其调用为

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

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);

Since I couldn't find any working solution for Picasso I'm posting my complete and working(July 2020) example using Picasso below.由于我找不到毕加索的任何可行解决方案,因此我将在下面使用毕加索发布完整且有效(2020 年 7 月)的示例。

It is sending the notification immediately and then updates it when the image for setLargeIcon() has been loaded.它立即发送通知,然后在加载 setLargeIcon() 的图像时更新它。 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?
                        }
                    });
        }
    });


}

RxJava and Picasso way RxJava 和毕加索方式

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")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM