Java “警告:不要在静态字段中放置 Android 上下文类;这是内存泄漏(也会破坏 Instant Run)”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40094020/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:23:43  来源:igfitidea点击:

"Warning: Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)"

javaandroidmemory-leaksandroid-volley

提问by X09

Similar question have been asked here, hereand herebut the context is quite different from this and moreover the code that gave from this erroris written by the makers of Android and Android Studio.

类似的问题在这里这里这里都被问过,但上下文与完全不同,而且从这个错误中给出代码是由 Android 和 Android Studio 的制造商编写的。

This is the code:

这是代码:

public class MySingleton {
    private static MySingleton mInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Context mCtx;

    private MySingleton(Context context) {
        mCtx = context;
        mRequestQueue = getRequestQueue();

        mImageLoader = new ImageLoader(mRequestQueue,
                new ImageLoader.ImageCache() {
            private final LruCache<String, Bitmap>
                    cache = new LruCache<String, Bitmap>(20);

            @Override
            public Bitmap getBitmap(String url) {
                return cache.get(url);
            }

            @Override
            public void putBitmap(String url, Bitmap bitmap) {
                cache.put(url, bitmap);
            }
        });
    }

    public static synchronized MySingleton getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new MySingleton(context);
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
        }
        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req) {
        getRequestQueue().add(req);
    }

    public ImageLoader getImageLoader() {
        return mImageLoader;
    }
}

The lines giving the warning are:

发出警告的行是:

private static MySingleton mInstance;
private static Context mCtx;

Now if I remove the statickeyword, change public static synchronized MySingleton getInstance(Context...to public synchronized MySingleton getInstance(Context...the error disappers but another problem comes up.

现在,如果我删除static关键字,更改public static synchronized MySingleton getInstance(Context...public synchronized MySingleton getInstance(Context...错误会消失,但会出现另一个问题。

I use MySingletonin RecyclerView. So this line

MySingleton在 RecyclerView 中使用。所以这一行

@Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { ImageLoader imageLoader = MySingleton.getInstance(mContext).getImageLoader();

@Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { ImageLoader imageLoader = MySingleton.getInstance(mContext).getImageLoader();

tells me

告诉我

Non-static method 'getInstance(android.content.Context)' cannot be refrenced from a static context.

非静态方法 'getInstance(android.content.Context)' 不能从静态上下文中引用。

Please anybody knows how to fix this?

请问有人知道如何解决这个问题吗?

采纳答案by X09

I found the solution to this in the answer to a similar question answered by CommonsWare

我在CommonsWare 回答的类似问题的回答中找到了解决方案

I quote

我引用

The quoted Lint warning is not complaining about creating singletons. It is complaining about creating singletons holding a reference to an arbitrary Context, as that could be something like an Activity. Hopefully, by changing mContext = context to mContext = context.getApplicationContext(), you will get rid of that warning (though it is possible that this still breaks Instant Run — I cannot really comment on that).

Creating singletons is fine, so long as you do so very carefully, to avoid memory leaks (e.g., holding an indefinite static reference to an Activity).

引用的 Lint 警告并不是在抱怨创建单例。它抱怨创建持有对任意上下文的引用的单例,因为这可能类似于活动。希望通过将 mContext = context 更改为 mContext = context.getApplicationContext(),您将摆脱该警告(尽管这可能仍会中断 Instant Run — 我无法对此发表评论)。

创建单例很好,只要您非常小心地这样做,以避免内存泄漏(例如,保持对活动的无限静态引用)。

So Google is not actually contracting itself. To fix this, if this.getApplicationContextis supplied as a parameter for the context, then there will be no memory leak.

所以谷歌实际上并没有与自己签约。为了解决这个问题,如果this.getApplicationContext作为上下文的参数提供,则不会有内存泄漏。

So in essence, ignore the warning and supply this.getApplicationContextas a parameter for the context.

所以本质上,忽略警告并this.getApplicationContext作为上下文的参数提供。

回答by Arst

I ended up putting this in AppController which has no warning.

我最终把它放在没有警告的 AppController 中。

public class AppController extends MultiDexApplication {

    public static Context getContext() {
        return mInstance.getApplicationContext();
    }

    private static AppController mInstance;

    public static synchronized AppController getInstance() {
        return mInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mInstance = this;

    }
}

So whenever you need it just call AppController.getContext()

所以只要你需要它就打电话 AppController.getContext()

回答by Montwell

This was my solution. There is no need to hold a static reference when you're just returning the instance of the RequestQueue?

这是我的解决方案。当您只是返回 RequestQueue 的实例时,是否不需要持有静态引用?

public class VolleyRequestQueue {

    private static VolleyRequestQueue mInstance;
    private RequestQueue mRequestQueue;

    private VolleyRequestQueue() {

    }

    public static synchronized VolleyRequestQueue getInstance() {
        if(mInstance == null) {
            mInstance = new VolleyRequestQueue();
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue(Context context) {
        if(mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(context.getApplicationContext());
        }
        return mRequestQueue;
    }
}