You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Service中使用Picasso Target加载URL Bitmap失败问题

解决Service中Picasso Target无法获取Bitmap的问题

Hey, I’ve run into this exact issue before! The core problem here is that Picasso holds a weak reference to your Target instance by default. Since you’re using an anonymous inner class for Target, there’s no strong reference keeping it alive. By the time Picasso finishes the network request or bitmap processing, the Target might have already been garbage collected (GC’d), which means none of the callback methods will fire.

解决方案1:将Target定义为Service的成员变量(最推荐)

把Target改成Service类的成员变量,让Service持有一个强引用,这样GC就不会提前回收它:

public class YourService extends Service {
    private static final String TAG = "YourService";
    // 定义成员变量保存Target实例
    private Target picassoBitmapTarget;

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化Target
        picassoBitmapTarget = new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                Log.e(TAG, "Picasso got bitmap!");
                showMMS(bitmap);
            }

            @Override
            public void onBitmapFailed(Exception e, Drawable errorDrawable) {
                Log.e(TAG, "Picasso Error : " + e.getMessage());
            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {
                Log.e(TAG, "Picasso is working...");
            }
        };
    }

    // 调用Picasso加载图片的方法
    private void loadImageWithPicasso(String imageUrl) {
        Picasso.get()
                .load(imageUrl)
                .into(picassoBitmapTarget);
    }

    // 记得在Service销毁时清理资源
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 取消未完成的请求,避免内存泄漏
        Picasso.get().cancelRequest(picassoBitmapTarget);
    }

    // 你的其他方法...
    private void showMMS(Bitmap bitmap) {
        // 处理Bitmap的逻辑
    }
}

解决方案2:使用Tag让Picasso持有强引用

如果不想用成员变量,可以给Picasso请求设置一个Tag(比如Service实例本身),Picasso会强引用这个Tag,间接保住Target不被GC回收:

private void loadImageWithPicasso(String imageUrl) {
    Target tempTarget = new Target() {
        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            Log.e(TAG, "Picasso got bitmap!");
            showMMS(bitmap);
        }

        @Override
        public void onBitmapFailed(Exception e, Drawable errorDrawable) {
            Log.e(TAG, "Picasso Error : " + e.getMessage());
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {
            Log.e(TAG, "Picasso is working...");
        }
    };

    Picasso.get()
            .load(imageUrl)
            .tag(this) // 传入Service实例作为Tag
            .into(tempTarget);
}

// 同样要在Service销毁时取消请求
@Override
public void onDestroy() {
    super.onDestroy();
    Picasso.get().cancelTag(this);
}

解决方案3:使用Picasso的同步加载(适合无UI场景)

因为Service没有UI,也可以直接用同步方法获取Bitmap,这种方式不需要依赖Target,但必须在子线程执行,否则会阻塞主线程:

private void loadImageSync(String imageUrl) {
    new Thread(() -> {
        try {
            // 同步获取Bitmap
            Bitmap bitmap = Picasso.get()
                    .load(imageUrl)
                    .get();
            // 如果showMMS需要在主线程执行,切换回主线程
            runOnUiThread(() -> showMMS(bitmap));
        } catch (IOException e) {
            Log.e(TAG, "Picasso Error : " + e.getMessage());
        }
    }).start();
}

额外注意事项

  • 确保你的Service拥有网络权限:在AndroidManifest.xml中添加<uses-permission android:name="android.permission.INTERNET"/>和<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>。
  • 如果你的图片URL是HTTP协议(非HTTPS),在Android 9及以上需要在AndroidManifest.xml的<application>标签中添加android:usesCleartextTraffic="true",否则会被系统拦截。
  • 先打印url_img+vo.getFile()拼接后的完整URL,验证是否能正常访问(比如在浏览器打开看看是否能加载图片)。

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:26:37