VolleyInstance中的Android上下文泄漏

时间:2017-04-18 06:09:44

标签: android memory-leaks android-context

我最近使用Volley库实现了单例模式。我在谷歌的开发者培训页面上提到了this实施:

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

}

如果有人将上述单身实例化为

RequestQueue queue = MySingleton.getInstance(this). getRequestQueue();

它会导致mCtx泄漏,因为它被声明为静态。

他们不应该只将Singleton的实现更改为:

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.getApplicationContext()); // <--Already using application 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);
    }
    return mRequestQueue;
}

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

public ImageLoader getImageLoader() {
    return mImageLoader;
}

}

我已将mInstance = new MySingleton(context);更改为mInstance = new MySingleton(context.getApplicationContext());

我的问题是:为什么要让用户发送应用程序上下文?为什么不在这堂课内保护?有什么想法吗?

2 个答案:

答案 0 :(得分:0)

重要的是使用APPLICATION上下文创建它:

RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
getRequestQueue();

由于Application上下文存在于应用程序生命周期的整个时间,因此不会导致内存泄漏。

答案 1 :(得分:0)

你可以使用应用程序上下文,但除此之外没有什么可做的,请记住只要app正在运行就存在Context ..所以你真的不能泄漏上下文。您可以尝试从您的应用中的ApplicationController获取上下文,但它仍然与上下文完全相同:

private MySingleton() {
    mCtx = ApplicationController.getContext();
    mRequestQueue = getRequestQueue();
    ...

并在应用 class中定义getContext(),如下所示:

public class ApplicationController extends Application {

    public static Context getContext(){
        return mContext;
    }

    ...