Android静态变量在服务中与在活动中不同
我希望有人能帮我弄清楚我的代码里发生了什么。我有一个代码块读写到我的数据库,它是从服务和我的活动中运行的。我需要这段代码是线程安全的,不管它是从服务还是从活动中调用的。因此,我采用了代码块所在的类,并创建了一个静态锁定对象,以保持其线程安全,正如您在下面的代码块中所看到的:Android静态变量在服务中与在活动中不同,android,multithreading,android-service,classloader,Android,Multithreading,Android Service,Classloader,我希望有人能帮我弄清楚我的代码里发生了什么。我有一个代码块读写到我的数据库,它是从服务和我的活动中运行的。我需要这段代码是线程安全的,不管它是从服务还是从活动中调用的。因此,我采用了代码块所在的类,并创建了一个静态锁定对象,以保持其线程安全,正如您在下面的代码块中所看到的: synchronized(AnalyticsMessages.sync_lock){ Log.v("mixpanel", "locking off of: "+AnalyticsMessage
synchronized(AnalyticsMessages.sync_lock){
Log.v("mixpanel", "locking off of: "+AnalyticsMessages.sync_lock.toString());
String[] eventsData = mDbAdapter.generateDataString(table);
if (eventsData != null) {
String lastId = eventsData[0];
String rawMessage = eventsData[1];
HttpPoster poster = getPoster(mEndpointHost, mFallbackHost);
HttpPoster.PostResult eventsPosted = poster.postData(rawMessage, endpointUrl);
if (eventsPosted == HttpPoster.PostResult.SUCCEEDED) {
logAboutMessageToMixpanel("Posted to " + endpointUrl);
logAboutMessageToMixpanel("Sent Message\n" + rawMessage);
//Log.v("mixpanel", "Sent Message\n" + rawMessage);
mDbAdapter.cleanupEvents(lastId, table);
Log.v("mixpanel", "removing id: "+lastId);
}
else if (eventsPosted == HttpPoster.PostResult.FAILED_RECOVERABLE) {
// Try again later
if (!hasMessages(FLUSH_QUEUE)) {
sendEmptyMessageDelayed(FLUSH_QUEUE, mFlushInterval);
}
}
else { // give up, we have an unrecoverable failure.
mDbAdapter.cleanupEvents(lastId, table);
}
}
}
sync_lock在分析消息中定义如下:
private static final Object sync_lock = new Object();
public static AnalyticsMessages getInstance(Context messageContext) {
synchronized (sInstances) {
Context appContext = messageContext.getApplicationContext();
AnalyticsMessages ret;
if (! sInstances.containsKey(appContext)) {
if (MPConfig.DEBUG) Log.d(LOGTAG, "Constructing new AnalyticsMessages for Context " + appContext);
ret = new AnalyticsMessages(appContext);
sInstances.put(appContext, ret);
}
else {
if (MPConfig.DEBUG) Log.d(LOGTAG, "AnalyticsMessages for Context " + appContext + " already exists- returning");
ret = sInstances.get(appContext);
}
return ret;
}
}
很明显,它没有正确锁定,因此日志带有toString。日志告诉我,我似乎有两个不同的sync_lock变量(因为它在内存中打印地址)。我应该提到,AnalyticsMessages是这样实例化的:
private static final Object sync_lock = new Object();
public static AnalyticsMessages getInstance(Context messageContext) {
synchronized (sInstances) {
Context appContext = messageContext.getApplicationContext();
AnalyticsMessages ret;
if (! sInstances.containsKey(appContext)) {
if (MPConfig.DEBUG) Log.d(LOGTAG, "Constructing new AnalyticsMessages for Context " + appContext);
ret = new AnalyticsMessages(appContext);
sInstances.put(appContext, ret);
}
else {
if (MPConfig.DEBUG) Log.d(LOGTAG, "AnalyticsMessages for Context " + appContext + " already exists- returning");
ret = sInstances.get(appContext);
}
return ret;
}
}
似乎是这样的,当服务将自身作为上下文传递给AnalyticsMessages.getInstance时,我最终得到一个sync_lock变量,但当我的一个活动将自身作为上下文传递给此处时,我最终得到另一个变量?这是否意味着android服务使用与主进程不同的类加载器?有解决办法吗?我认为这实际上是一个比较普遍的问题?我是不是完全偏离了轨道?提前谢谢
我的后台服务似乎使用了android:process
这是造成这种特殊困难的一个常见原因。虽然,从Java源代码的角度来看,这都是一个应用程序,但您运行两个单独的进程这一事实意味着您有两个单独的对象堆,因此一个堆中的全局(静态数据成员)将不同于另一个堆中相同的命名全局
是否有充分的理由让服务运行在与应用程序其余部分不同的进程中
通常不会。正如您所看到的,它会导致应用程序消耗更多内存和CPU时间,并限制各种组件(在不同进程中运行)的互操作能力。我通常反对多个过程。话虽如此,更改它将需要进行彻底的测试,特别是如果您不知道为什么要首先使用该技术。您是否在清单中使用了
android:process
属性?实际上,我没有编写代码,但似乎android:process用于我的后台服务。这听起来像是罪魁祸首,但现在我有点担心关掉它。是否有充分的理由让服务在不同于应用程序其余部分的进程中运行?此外,我非常感谢您的帮助,如果您将此作为答案发布,我会将其标记为正确。可能服务是在应用程序之外的单独进程中运行的,因为当用户从最近的应用程序关闭应用程序时,它不应该被杀死?