web-dev-qa-db-fra.com

"Avertissement: ne placez pas Android dans les champs statiques; il s'agit d'une fuite de mémoire (et qui rompt également l'exécution instantanée)".

Une question similaire a été posée ici , ici et ici mais le contexte est assez différent de cela et en plus le code qui a donné de cette erreur est écrite par les créateurs de Android et Android Studio.

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

Les lignes donnant l'avertissement sont:

private static MySingleton mInstance;
private static Context mCtx;

Maintenant, si je supprime le mot clé static, remplacez public static synchronized MySingleton getInstance(Context... Par public synchronized MySingleton getInstance(Context... L'erreur disparaît mais un autre problème survient.

J'utilise MySingleton dans RecyclerView. Donc cette ligne

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

dit moi

La méthode non statique 'getInstance (Android.content.Context)' ne peut pas être référencée à partir d'un contexte statique.

S'il vous plaît, quelqu'un sait comment résoudre ce problème?

13
X09

J'ai trouvé la solution à cela dans le réponse à une question similaire répondue par CommonsWare

Je cite

L'avertissement Lint cité ne se plaint pas de la création de singletons. Il se plaint de créer des singletons contenant une référence à un contexte arbitraire, car cela pourrait être quelque chose comme une activité. Avec un peu de chance, en changeant mContext = context en mContext = context.getApplicationContext (), vous vous débarrasserez de cet avertissement (bien qu'il soit possible que cela casse toujours Instant Run - je ne peux pas vraiment commenter cela).

La création de singletons est très bien, tant que vous le faites très soigneusement, pour éviter les fuites de mémoire (par exemple, en maintenant une référence statique indéfinie à une activité).

Donc, Google ne se contracte pas réellement. Pour résoudre ce problème, si this.getApplicationContext est fourni comme paramètre pour le contexte, il n'y aura donc pas de fuite de mémoire.

Donc, en substance, ignorez l'avertissement et fournissez this.getApplicationContext comme paramètre pour le contexte.

15
X09

J'ai fini par mettre cela dans AppController qui n'a aucun avertissement.

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;

    }
}

Donc, chaque fois que vous en avez besoin, appelez simplement AppController.getContext()

4
Arst