2017-04-18 29 views
-1

我最近使用Volley库作为单例模式实现。我提到this实现谷歌的开发人员培训页:Android上下文泄漏VolleyInstance

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泄漏,因为它是声明为静态。

难道他们不应该只是改变辛格尔顿来实现:

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());

我的问题是:为什么它留给用户发送应用程序上下文?为什么不保护这个班级?有什么想法吗?

+0

在开发者网站上的实现一切都很好,你唯一需要做的就是始终发送应用程序上下文,而不是活动上下文。 –

+0

这就是要点。为什么让用户发送应用程序上下文?为什么不保护这个班级? –

+0

如果您将应用程序上下文用作静态,则不会发生内存泄漏,因为应用程序上下文通过应用程序存在。 –

回答

0

重要的是使用应用程序上下文来创建它:

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

因为应用程序上下文中的应用程序生命周期它不能导致内存泄漏的existsthe全部时间。

+0

这就是我所指的。为什么让用户发送应用程序上下文?为什么不在这个类中保护并始终使用应用程序上下文? –

0

那么你可以使用应用上下文但除此之外,没有什么太大的事,记得Context的应用程序正在运行,只要存在。所以你真的不能泄露语境。你可以尝试在你的应用程序从ApplicationController获取上下文,但它仍然是完全一样的关于语境:

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

,并在您应用class定义getContext()这样的:

public class ApplicationController extends Application { 

    public static Context getContext(){ 
     return mContext; 
    } 

    ...