Android Studio:
不要将Android上下文类放在静态字段中;这是一个 内存泄漏(也打破了Instant Run)
所以2个问题:
#1如果没有静态变量用于上下文,如何从静态方法调用startService
?
#2如何从静态方法发送localBroadcast(相同)?
示例:
public static void log(int iLogLevel, String sRequest, String sData) {
if(iLogLevel > 0) {
Intent intent = new Intent(mContext, LogService.class);
intent.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
mContext.startService(intent);
}
}
或
Intent intent = new Intent(MAIN_ACTIVITY_RECEIVER_INTENT);
intent.putExtra(MAIN_ACTIVITY_REQUEST_FOR_UPDATE, sRequest));
intent.putExtra(MAIN_ACTIVITY_DATA_FOR_VIEW, sData);
intent.putExtra(MAIN_ACTIVITY_LOG_LEVEL, iLogLevel);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
在不使用mContext
的情况下执行此操作的正确方法是什么?
注意:我认为我的主要问题可能是如何将上下文传递给调用方法所在的类。
答案 0 :(得分:47)
如果您决定将其存储在任何成员字段中,请确保在通过methods / constructor传递给您的单例的任何上下文中传递context.getApplicationContext()或调用getApplicationContext()。
白痴证明示例(即使有人会传入一个活动,它会抓住应用程序上下文并使用它来实例化单例):
public static synchronized RestClient getInstance(Context context) {
if (mInstance == null) {
mInstance = new RestClient(context.getApplicationContext());
}
return mInstance;
}
getApplicationContext()根据文档:“返回当前进程的单个全局Application对象的上下文。”
这意味着“getApplicationContext()”返回的上下文将贯穿整个过程,因此如果您在任何地方存储静态引用并不重要,因为它会在您的应用程序运行期间始终存在(并且比任何实例化的对象/单身人士都活得更长。
将其与持有大量数据的视图/活动内的上下文进行比较,如果泄漏活动持有的上下文,系统将无法释放显然不好的资源。
通过其上下文对活动的引用应该与活动本身处于相同的生命周期,否则它将保持上下文人质导致内存泄漏(这是lint警告背后的原因)。
编辑:对于从上述文档中抨击示例的人来说,代码中甚至还有关于我刚才所写内容的评论部分:
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
答案 1 :(得分:45)
只需将其作为参数传递给您的方法即可。创建Context
的静态实例仅用于启动Intent
是没有意义的。
这是您的方法的外观:
public static void log(int iLogLevel, String sRequest, String sData, Context ctx) {
if(iLogLevel > 0) {
Intent intent = new Intent(ctx, LogService.class);
intent1.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
ctx.startService(intent);
}
}
从问题评论中更新:将初始活动的上下文(通过构造函数参数或方法参数)级联到您需要的位置。
答案 2 :(得分:4)
这只是一个警告。别担心。如果您想使用应用程序上下文,可以将其保存在" singleton" class,用于保存项目中的所有单例类。
答案 3 :(得分:1)
在你的情况下,将它作为静态字段没有多大意义,但我不认为它在所有情况下都不好。如果您现在正在做什么,您可以使用具有上下文的静态字段,稍后将其置零。我正在为我的主模型类创建静态实例,其中包含上下文,其应用程序上下文不是活动上下文,并且我还有包含Activity的类的静态实例字段,我在destroy上为null。我没有看到我有内存泄漏。所以,如果一些聪明的家伙认为我错了,请随意评论......
Instant Run在这里工作得很好......
答案 4 :(得分:1)
通常,避免将上下文字段定义为静态。警告本身解释了原因:这是内存泄漏。打破即时运行可能不是这个星球上最大的问题。
现在,您有两种情况可以获得此警告。对于一个实例(最明显的一个):
Things
然后有一点比较棘手,其中上下文包含在一个类中:
public static Context ctx;
该类在某处被定义为static:
public class Example{
public Context ctx;
//Constructor omitted for brievety
}
你会得到警告。
解决方案本身非常简单:不要在静态实例中放置上下文字段,无论是包装类还是直接声明静态实例。
警告的解决方案很简单:不要静态放置字段。在您的情况下,将上下文作为实例传递给方法。对于进行多个Context调用的类,使用构造函数将上下文(或者就此而言的Activity)传递给类。
请注意,这是一个警告,而不是错误。如果您出于某种原因需要静态上下文,您可以这样做。虽然你这样做会造成内存泄漏。 子>
答案 5 :(得分:1)
WeakReference
将上下文存储在Singleton类中,警告将消失private WeakReference<Context> context;
//Private contructor
private WidgetManager(Context context) {
this.context = new WeakReference<>(context);
}
//Singleton
public static WidgetManager getInstance(Context context) {
if (null == widgetManager) {
widgetManager = new WidgetManager(context);
}
return widgetManager;
}
现在您可以像访问上下文一样
if (context.get() instanceof MainActivity) {
((MainActivity) context.get()).startActivityForResult(pickIntent, CODE_REQUEST_PICK_APPWIDGET);
}
答案 6 :(得分:0)
如果您确定它是一个应用程序上下文。没关系。添加
@SuppressLint("StaticFieldLeak")