最佳的通知图片加载方式是什么?

4

什么是加载通知图片的最佳方式?

这是我目前的方式:如您所见,图像同步加载,因此通知可能会延迟。这是一种不好的方式。

public Bitmap getBitmapFromURL(String strURL) {
    try {
        URL url = new URL(strURL);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoInput(true);
        connection.connect();
        InputStream input = connection.getInputStream();
        Bitmap myBitmap = BitmapFactory.decodeStream(input);
        return myBitmap;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

Bitmap bitmap = getBitmapFromURL("https://graph.facebook.com/YOUR_USER_ID/picture?type=large");

// CONSTRUCT THE NOTIFICATION DETAILS
builder.setAutoCancel(true);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("Some Title");
builder.setContentText("Some Content Text");
builder.setLargeIcon(bitmap);
builder.setContentIntent(pendingIntent);

我真的需要一个答案才能继续进行我的项目。


Stack Overflow不是一个编程比赛。我们要求问题必须有一个明确、可验证的答案。询问“最好的”并不起作用。你需要精确地缩小你所说的“最好”的范围。你的要求是什么?你有什么限制?描述你正在寻找的解决方案,然后有人可以提供它。 - Cody Gray
3个回答

4

首先,您应该使用没有图像或占位符的通知,然后使用AsyncTask加载位图,或者使用Picasso和Target回调函数。

将您的任务提供给第一个通知所使用的构建器,在位图加载完成后,将其添加到构建器中,然后重新通知您的通知。

如果在完全加载图像之前存在内容已更改的风险,请存储一个标识当前要显示内容的变量,以便在重新通知之前进行检查。

您可以参考Google提供的MediaNotificationManager示例,UniversalMusicPlayer项目。

在您的情况下:

// CONSTRUCT THE NOTIFICATION DETAILS
builder.setAutoCancel(true);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("Some Title");
builder.setContentText("Some Content Text");
//builder.setLargeIcon(bitmap); // replace this line with place holder drawable from resources
builder.setContentIntent(pendingIntent);

manager.notify(NOTIFICATION_ID, builder.build());

currentLoadImageTask = new LoadImageTask(manager, builder);
currentLoadImageTask.execute("https://graph.facebook.com/YOUR_USER_ID/picture?type=large");

// ...

static class LoadImageTask extends AsyncTask<String, Void, Bitmap> {

    final NotificationManager manager;
    final NotificationCompat.Builder builder;

    public LoadImageTask(final NotificationManager manager, final NotificationCompat.Builder builder) {
        this.manager = manager;
        this.builder = builder;
    }

    @Override
    protected Bitmap doInBackground(final String... strings) {
        if (strings == null || strings.length == 0) {
            return null;
        }
        try {
            final URL url = new URL(strings[0]);
            final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            final InputStream input = connection.getInputStream();
            return BitmapFactory.decodeStream(input);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    protected void onPostExecute(final Bitmap bitmap) {
        if (bitmap == null || manager == null || builder == null) {
            return;
        }
        builder.setLargeIcon(bitmap);
        manager.notify(NOTIFICATION_ID, builder.build());
    }
}

使用 Picasso:

// CONSTRUCT THE NOTIFICATION DETAILS
builder.setAutoCancel(true);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("Some Title");
builder.setContentText("Some Content Text");
//builder.setLargeIcon(bitmap); // replace this line with place holder drawable from resources
builder.setContentIntent(pendingIntent);

manager.notify(NOTIFICATION_ID, builder.build());

// ...

Picasso.with(context)
    .load("https://graph.facebook.com/YOUR_USER_ID/picture?type=large")
    .resize(250, 250)
    .into(new Target() {
        @Override
        public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) {
            builder.setLargeIcon(bitmap);
            manager.notify(NOTIFICATION_ID, builder.build());
        }

        @Override
        public void onBitmapFailed(final Drawable errorDrawable) {
             // Do nothing
        }

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

如果不在UI线程中,你可以创建一个Runnable并在Looper中执行它。

 final Handler uiHandler = new Handler(Looper.getMainLooper());
 uiHandler.post(new Runnable() {
      @Override
      public void run() {
           // Call from here
      }
 });

使用缓存,Picasso更好。

我强烈建议您调整设置在通知中的每个位图的大小,因为如果不这样做,很容易引发OutOfMemoryException。


这不是“经典”的方式,你不能直接通过into()方法引用你的imageView,但在你的情况下,你必须获取加载的位图结果,因为通知管理器不允许你访问imageview。使用Target是如何使用picasso异步获取位图加载结果的。http://square.github.io/picasso/2.x/picasso/com/squareup/picasso/RequestCreator.html#into-com.squareup.picasso.Target- - smora
我在这一行 .into(new Target() { 遇到了错误 java.lang.IllegalStateException: Method call should happen from the main thread. - user8458395
我该如何修复这个错误? - user8458395
我正在尝试从OnMessageReceived中加载图像。请在此处查看该方法:https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java - user8458395
有很多种方法,我在我的答案中添加了其中一种。 - smora
显示剩余2条评论

3
请注意,如果您正在使用网络加载某些内容,则需要等待一段时间。有几种解决方案:
  1. 像您的示例一样从Web中加载图像并显示。
  2. 显示一个存根图像,并通过更新通知后稍后显示下载的图像
  3. 使用一点帮助来缓存Web英寸的工具。例如,Picaso
http://square.github.io/picasso/

0

使用Picasso库从URL加载图片,例如:

 Picasso.with(this.load(imageUri).into(imageview_id);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接