UPDATE 2/13/2012:接受了一個答案,解釋說這種行爲是一個錯誤,並指出它似乎已經在仿真器上消失得比1.6版更好,這對我們大多數人來說都不是問題。解決方法是簡單地循環/休眠直到getContext()。getApplicationContext()返回非空。 END UPDATE爲什麼AndroidTestCase.getContext()。getApplicationContext()返回null?
根據android.app.Application javadoc,我定義了一個單例(稱爲數據庫),我的所有活動都可以訪問狀態數據和持久數據,而Database.getDatabase(Context)通過上下文獲取應用程序上下文。 getApplicationContext()。此設置按照活動傳遞給getDatabase(Context)時的通告方式工作,但是當我從AndroidTestCase運行單元測試時,getApplicationContext()調用通常返回null,儘管測試時間越長,返回非空的頻率越高值。
以下代碼重現了AndroidTestCase中的null - 單例不是演示必需的。
首先,爲了記錄應用程序實例化消息,在測試的應用程序中,我定義了MyApp並將其添加到清單中。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Log.i("MYAPP", "this=" + this);
Log.i("MYAPP", "getAppCtx()=" + getApplicationContext());
}
}
接下來,我所定義的測試用例來上AndroidTestCase.getContext()4次報告,由一些睡覺和getSharedPreferences)分開(呼叫:
public class DatabaseTest extends AndroidTestCase {
public void test_exploreContext() {
exploreContexts("XPLORE1");
getContext().getSharedPreferences("foo", Context.MODE_PRIVATE);
exploreContexts("XPLORE2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
exploreContexts("XPLORE3");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
exploreContexts("XPLORE4");
}
public void exploreContexts(String tag) {
Context testContext = getContext();
Log.i(tag, "testCtx=" + testContext +
" pkg=" + testContext.getApplicationInfo().packageName);
Log.i(tag, "testContext.getAppCtx()=" + testContext.getApplicationContext());
try {
Context appContext = testContext.createPackageContext("com.foo.android", 0);
ApplicationInfo appInfo = appContext.getApplicationInfo();
Log.i(tag, "appContext=" + appContext +
" pkg=" + appContext.getApplicationInfo().packageName);
Log.i(tag, "appContext.getAppCtx()=" + appContext.getApplicationContext());
} catch (NameNotFoundException e) {
Log.i(tag, "Can't get app context.");
}
}
}
這是的一個塊導致logcat的(通過Eclipse 1.6模擬器上SDK11的WinXP):在getApplicationContext()一會兒返回null,然後開始返回MyApp的實例
INFO/TestRunner(465): started: test_exploreContext(test.foo.android.DatabaseTest)
INFO/XPLORE1(465): [email protected] pkg=com.foo.android
INFO/XPLORE1(465): testContext.getAppCtx()=null
INFO/XPLORE1(465): [email protected] pkg=com.foo.android
INFO/XPLORE1(465): appContext.getAppCtx()=null
INFO/XPLORE2(465): [email protected] pkg=com.foo.android
INFO/XPLORE2(465): testContext.getAppCtx()=null
INFO/XPLORE2(465): [email protected] pkg=com.foo.android
INFO/XPLORE2(465): appContext.getAppCtx()=null
INFO/MYAPP(465): [email protected]
INFO/MYAPP(465): getAppCtx()[email protected]
INFO/XPLORE3(465): [email protected] pkg=com.foo.android
INFO/XPLORE3(465): testContext.getAppCtx()[email protected]
INFO/XPLORE3(465): [email protected] pkg=com.foo.android
INFO/XPLORE3(465): appContext.getAppCtx()[email protected]
INFO/XPLORE4(465): [email protected] pkg=com.foo.android
INFO/XPLORE4(465): testContext.getAppCtx()[email protected]
INFO/XPLORE4(465): [email protected] pkg=com.foo.android
INFO/XPLORE4(465): appContext.getAppCtx()[email protected]
INFO/TestRunner(465): finished: test_exploreContext(test.foo.android.DatabaseTest)
通知。在這個測試的不同運行中,我一直無法得到完全相同的結果(這就是我最終在4次迭代,睡眠以及getSharedPreferences()的嘗試嘗試讓應用程序存在的結果)。
上面的LogCat消息塊似乎最相關,但單個測試的單次運行的整個LogCat很有趣。 Android開始了4個AndroidRuntimes;上面的塊是從第四個。有趣的是,第三運行時顯示錶示其實例MyApp的的不同實例在進程ID 447的消息:
INFO/TestRunner(447): started: test_exploreContext(test.foo.android.DatabaseTest)
INFO/MYAPP(447): [email protected]
INFO/MYAPP(447): getAppCtx()[email protected]
INFO/TestRunner(447): finished: test_exploreContext(test.foo.android.DatabaseTest)
我假定TestRunner的(447)消息是從在過程465在其孩子父母測試線程報告。問題仍然存在:爲什麼Android會在其上下文正確連接到Application實例之前讓AndroidTestCase運行?
解決方法:如果我先撥打getContext().getSharedPreferences("anyname", Context.MODE_PRIVATE).edit().clear().commit();
,我的一個測試似乎在大多數情況下避免了空值,所以我正在使用它。
BTW:如果答案是「這是一個Android錯誤,爲什麼不提交它;哎呀,你爲什麼不修復它?那麼我願意做這兩件事。我還沒有成爲一個bug編制者或貢獻者的步驟 - 也許這是一個好時機。
我注意到AndroidTestCase也有一些奇怪的行爲。通常情況下,每個測試運行多次,但只向Eclipse報告一次。例如,我有時會在'onDestroy'中得到'Nullpointer'異常,而所有實例字段都在'onCreate'中正確初始化。你可以通過在'onDestroy'中放置一個斷點來檢驗這一點,並且看到執行至少有四次,而測試只運行一次。 – siamii
我在Android 4.0.4模擬器上遇到了同樣的問題,ApplicationContext有時會在那裏,有時候不會。你的解決方法,直到它在那裏似乎工作。 – Ralf
對於使用SDK 10在模擬器HAX上運行的測試,我也會看到它。否則,看起來錯誤不能再生成。 – Snicolas