Предупреждение: не размещайте классы контекста Android в статических полях, это утечка памяти (а также прерывает Instant Run) "

Аналогичный вопрос был здесь, здесь и здесь, но контекст сильно отличается от этого, и более того код, который дал от этой ошибки, написан разработчиками Android и Android Студия.

Это код:

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

Строки с предупреждением:

private static MySingleton mInstance;
private static Context mCtx;

Теперь, если я удалю ключевое слово static, измените public static synchronized MySingleton getInstance(Context... на public synchronized MySingleton getInstance(Context..., ошибка исчезнет, ​​но возникнет другая проблема.

Я использую MySingleton в RecyclerView. Итак, эта строка

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

говорит мне

Нестатический метод getInstance (android.content.Context) не может быть переопределен из статического контекста.

Пожалуйста, кто-нибудь знает, как это исправить?

Ответ 1

Я нашел решение этого в ответе на аналогичный вопрос, отвеченный CommonsWare

Я цитирую

Указанное предупреждение Lint не жалуется на создание синглонов. Он жалуется на создание синглтонов, содержащих ссылку на произвольный контекст, поскольку это может быть что-то вроде Activity. Надеюсь, изменив mContext = context на mContext = context.getApplicationContext(), вы избавитесь от этого предупреждения (хотя возможно, что это все еще прерывает Instant Run - я не могу действительно прокомментируйте это).

Создание синглетов в порядке, если вы делаете это очень осторожно, чтобы избегайте утечек памяти (например, удерживая неопределенную статическую ссылку на Activity).

Таким образом, Google фактически не сокращает себя. Чтобы исправить это, если this.getApplicationContext поставляется в качестве параметра для контекста, тогда утечки памяти не будет.

Таким образом, по существу, игнорируйте предупреждение и поставляйте this.getApplicationContext в качестве параметра для контекста.

Ответ 2

В итоге я положил это в 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;

    }
}

Поэтому, когда вам это нужно, просто позвоните AppController.getContext()

Ответ 3

Это было мое решение. Нет необходимости хранить статическую ссылку, когда вы просто возвращаете экземпляр 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;
    }
}

Ответ 4

Я написал этот одноэлементный класс и не обнаружил утечки памяти или другого предупреждения.

public class UtilSharedPrefernce {

 public class UtilSharedPrefernce {

    private static UtilSharedPrefernce mInstance;
    private SharedPreferences mMyPreferences;

     private UtilSharedPrefernce(){ }

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

    public void Initialize(Context ctxt){
        mMyPreferences = PreferenceManager.getDefaultSharedPreferences(ctxt);
    }

    public void writePreference(String key, String value){
        SharedPreferences.Editor e = mMyPreferences.edit();
        e.putString(key, value);
        e.apply();
    }

    public String readPreference(String key){
        return mMyPreferences.getString(key, "");

    }

}