Why does AndroidTestCase.getContext().getApplicationContext() return null? - android

UPDATE 2/13/2012: Accepted an answer, explained that this behavior is a bug, and noted that it appears to have disappeared on emulators better than v 1.6, which makes it a non-issue for most of us. The workaround is simply to loop/sleep until getContext().getApplicationContext() returns non-null.
END UPDATE
As per android.app.Application javadoc, I defined a singleton (called Database) that all of my activities access for state and persistent data, and Database.getDatabase(Context) gets the application context via Context.getApplicationContext(). This setup works as advertised when activities pass themselves to getDatabase(Context), but when I run a unit test from an AndroidTestCase, the getApplicationContext() call often returns null, though the longer the test, the more frequently it returns a non-null value.
The following code reproduces the null within an AndroidTestCase -- the singleton isn't necessary for the demonstration.
First, to log app-instantiation messages, in the app-under-test I defined MyApp and added it to the manifest.
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Log.i("MYAPP", "this=" + this);
Log.i("MYAPP", "getAppCtx()=" + getApplicationContext());
}
}
Next, I defined a test case to report on AndroidTestCase.getContext() 4 times, separated by some sleeps and a getSharedPreferences() call:
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.");
}
}
}
And this is a chunk of the resulting logCat (1.6 emulator on SDK11 WinXP via Eclipse):
INFO/TestRunner(465): started: test_exploreContext(test.foo.android.DatabaseTest)
INFO/XPLORE1(465): testCtx=android.app.ApplicationContext#43757368 pkg=com.foo.android
INFO/XPLORE1(465): testContext.getAppCtx()=null
INFO/XPLORE1(465): appContext=android.app.ApplicationContext#437801e8 pkg=com.foo.android
INFO/XPLORE1(465): appContext.getAppCtx()=null
INFO/XPLORE2(465): testCtx=android.app.ApplicationContext#43757368 pkg=com.foo.android
INFO/XPLORE2(465): testContext.getAppCtx()=null
INFO/XPLORE2(465): appContext=android.app.ApplicationContext#43782820 pkg=com.foo.android
INFO/XPLORE2(465): appContext.getAppCtx()=null
INFO/MYAPP(465): this=com.foo.android.MyApplication#43783830
INFO/MYAPP(465): getAppCtx()=com.foo.android.MyApplication#43783830
INFO/XPLORE3(465): testCtx=android.app.ApplicationContext#43757368 pkg=com.foo.android
INFO/XPLORE3(465): testContext.getAppCtx()=com.foo.android.MyApplication#43783830
INFO/XPLORE3(465): appContext=android.app.ApplicationContext#43784768 pkg=com.foo.android
INFO/XPLORE3(465): appContext.getAppCtx()=com.foo.android.MyApplication#43783830
INFO/XPLORE4(465): testCtx=android.app.ApplicationContext#43757368 pkg=com.foo.android
INFO/XPLORE4(465): testContext.getAppCtx()=com.foo.android.MyApplication#43783830
INFO/XPLORE4(465): appContext=android.app.ApplicationContext#43785778 pkg=com.foo.android
INFO/XPLORE4(465): appContext.getAppCtx()=com.foo.android.MyApplication#43783830
INFO/TestRunner(465): finished: test_exploreContext(test.foo.android.DatabaseTest)
Notice that getApplicationContext() returned null for a while, then started returning an instance of MyApp. I have not been able to get the exact same results in different runs of this test (that's how I ended up at 4 iterations, sleeps, and that call to getSharedPreferences() to try to goose the app into existence).
The chunk of LogCat messages above seemed most relevant, but the entire LogCat for that single run of that single test was interesting. Android started 4 AndroidRuntimes; the chunk above was from the 4th. Interestingly, the 3rd runtime displayed messages indicating that it instantiated a different instance of MyApp in process ID 447:
INFO/TestRunner(447): started: test_exploreContext(test.foo.android.DatabaseTest)
INFO/MYAPP(447): this=com.foo.android.MyApplication#437809b0
INFO/MYAPP(447): getAppCtx()=com.foo.android.MyApplication#437809b0
INFO/TestRunner(447): finished: test_exploreContext(test.foo.android.DatabaseTest)
I assume that the TestRunner(447) messages are from a parent test thread reporting on its children in process 465. Still, the question is: why does Android let an AndroidTestCase run before its context is properly hooked up to an Application instance?
Workaround: One of my tests seemed to avoid nulls most of the time if I called getContext().getSharedPreferences("anyname", Context.MODE_PRIVATE).edit().clear().commit(); first, so I'm going with that.
BTW: If the answer is "it's an Android bug, why don't you file it; heck, why don't you fix it?" then I'd be willing to do both. I haven't taken the step of being a bug-filer or contributor yet -- maybe this is a good time.

Instrumentation runs in a separate thread from the main app thread, so that it can execute without blocking or disrupting (or being blocked by) the main thread. If you need to synchronize with the main thread, use for example: Instrumentation.waitForIdleSync()
In particular, the Application object as well as all other top-level classes like Activity are initialized by the main thread. Your instrumentation thread is running at the same time those are initializing. This if you are touching any of those objects and are not implementing your own measures of thread safety, you should probably have such code run on the main thread such as via: Instrumentation.runOnMainSync(java.lang.Runnable)

As mentioned in the question and Dianne's answer (#hackbod), the Instrumentation runs on a separate thread. AndroidTestCase either has an implementation defect (missing synchronization) or it is not documented correctly. Unfortunately, there is no way to call Instrumentation.waitForIdleSync() from this particular test case class because the Instrumentation is not accessible from it.
This subclass can be used to add synchronization that polls getApplicationContext() until it returns a non-null value:
public class MyAndroidTestCase extends AndroidTestCase {
#Override
public void setContext(Context context) {
super.setContext(context);
long endTime = SystemClock.elapsedRealtime() + TimeUnit.SECONDS.toMillis(2);
while (null == context.getApplicationContext()) {
if (SystemClock.elapsedRealtime() >= endTime) {
fail();
}
SystemClock.sleep(16);
}
}
}
The polling and sleep durations are based on experience and can be tuned if necessary.

Related

Runtime error handling on android

I want to make some classes that catch runtime errors on android and offers the user the option to restore the last saved instance state of the app.
I was thinking of extending the Activity and Fragment classes and implement something that saves their state. In the meantime, another class handles every start of an activity or fragment, putting them in a stack.
I want to catch every possible exception in the app, hopefully making errors less bothersome for the user.
Any advice on how I should handle this?
How would this error checking influence the performance of an app?
It's not a good solution and i don't know if it's useful for you, but you can caught exceptions in Application Class.
public class MyApplication extends Application
{
public void onCreate ()
{
// Setup handler for uncaught exceptions.
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException (Thread thread, Throwable e)
{
handleUncaughtException (thread, e);
}
});
}
public void handleUncaughtException (Thread thread, Throwable e)
{
e.printStackTrace();
// do what ever you want.
}
}
You can use try catch blocks to catch runtime errors. If you use try catch efficiently with throws your app won't crash in first place hence no need to maintain stack of activities. btw maintaining stacks of previous activity in neither memory efficient nor advisable.

What is the use case for a Android Future?

For context, I am an Android developer who is familiar with using AsyncTask's but has recently started working on a project which is heavily using Future's. The Futures do not have a callback and require checks on isDone() to determine progress.
I am having trouble understanding what the purpose and use case of Future is in Android. AsyncTask's provide what seems like the same functionality but with in my opinion a better interface which has callbacks built in that enable the client to clearly determine when the async operation is complete without having to constantly check isDone().
What is the use and purpose of a Future in Android, and why would I use Future or FutureTask over an AsyncTask?
The Future is part of the Java API, whereas the AsyncTask is Android specific. In fact, if you take a look at the source code of AsyncTask, you will see that it actually uses a FutureTask for its implementation:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
#Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
The AsyncTask is thus just a helper class for short threading jobs, which also handles some thread pooling. My guess is that the original writers of your project were familiar with Futures, but not with AsyncTask, or generally disliked AsyncTask.
Since I dislike the original AsyncTask implementation due to its Exception handling, I went on a search for a better alternative, and found RoboGuice's SafeAsyncTask. In this implementation, an onException(Exception) callback is available, but RuntimeExceptions get propagated to that callback as well.
I think a NullPointerException should make the app just crash, and I modified this SafeAsyncTask a little while back to do exactly this. The result can be found here.

Refactor to fix architectural error

In a sort-of-working application I see this monstrous code:
class SomeUglyClass extends Thread {
ArrayList<SomeData> someDataStructure = new ArrayList<SomeData>();
Handler mHandler = new Handler() {
// a lot
// writing to someDataStructure
}
public void run() {
int some_count, ...;
while(true) {
// a lot
// r/w access to someDataStructure
try {
Thread.sleep(1, 0);
} catch (Exception e) {
break;
}
}
} // end of run(), total 500 lines of code
} // end of SomeUglyClass, total 4K lines of code
Maybe you already see the problems with this code. If not, here they are:
mHandler is attached to the UI thread (because it is created by the thread that loads the class, which is the main thread)
there's no looper (which is fact is the bug)
the thread wastes CPU time and drains the battery
someDataStructure is not thread-safe, but synchronizing elementary access operations will not help; synchronizing large blocks of code in a endless loop will likely block the guarded resource and make it unavailable for other threads; finally, it is not only someDataStructure, the whole class is based on the assumption that only one thread can run its code.
I cannot just add the looper, because the endless loop in run() has to be run, while Looper.loop(); also is an infinite loop. One thread cannot run two infinite loops.
Despite this epic architectural fail, the code is really doing something, it cannot be re-written at once, it is 4K lines of code, and often I can only guess what the code really does.
I need to refactor it. It should be a sequence of small steps preserving the functionality.
How do I refactor this terrific code?
You should try separation of concerns: try first to divide the whole class into many smallest one, each one responsible for doing/dealing with exactly one thing.
You may have something for data Access (read/write data), service (isolated business logic), and the UI. You may use event bus to decouple between objects (consider otto) and may be dependency injection (consider Dagger).
This process of separation will help you understand what each piece of code is doing and also the dependencies between the different parts, thus making writing unit/integration tests much easier.
Add lots of tests, use version control and then work as slowly as you need to.
The 1st step has been to change:
public void run() {
int some_count, ...;
while(true) {
// a lot
// r/w access to someDataStructure
try {
Thread.sleep(1, 0);
} catch (Exception e) {
break;
}
}
}
to:
#Override
public void run() {
Looper.prepare();
mHandler = new MyHandler();
mHandler.post(run_step);
Looper.loop();
}
Runnable run_step = new Runnable() {
int some_count, ...;
#Override
public void run()
{
//while(true) {
// a lot
// r/w access to someDataStructure
mIntoThreadHandler.postDelayed(this, 1);
//}
}
}
This preserves the functionality but still wastes CPU time. The urgent bug has been fixed, and the issue has been closed; I could not sell "must refactor to kill monstrous code" to my management, but I could sell "this can work faster if I refactor," so a new separate issue has been opened. UGH!
PS no chance to sell "lots of tests".

Job manager in Android

I have a task to run several different jobs in Android app. Each job is long-running and cosumes network, database and file system much. Each job can be run manually by user or scheduled by AlarmManager. It is very important that each job runs till the end, so it needs to continue running after user leaves the app, or even when user does not open the app at all. Jobs have some ID attribute like this:
class Job {
int id;
}
I need this hypothetical JobManager to receive jobs and sort them by ID. If a job with id = 1 is already running, then JobManager should skip all the subsequent jobs with id = 1 until this job is finished. But if a job is submitted with id = 2, then it is accepted and can be run in parallel with the first job.
The jobs should also to keep wake lock until completed, like it is done in CommonsWare's WakefulIntentService.
I have several ideas how to implement this, but all have their drawbacks:
Subclass of the Service class that runs always in background and is automatically restarted, when killed for some reason. Drawbacks: it consumes resources even if not running anything, it is running on UI thread, so we have to manage some threads that can be killed by system as usual, each client has to start the Service and nobody knows, when to stop it.
WakefulIntentService from CommonsWare. Drawbacks: because it is IntentService, it runs only sequentially, so it cannot check for existing running job.
Boolean "running" flag in the database for each job. Check it every time we want to run a job. Drawbacks: too many requests to db, difficult to implement properly, sometimes 2 equal jobs still can run in parallel, not sure about flags staying "true" in case of any unexpected error.
Existing library disigned for this purpose. As for now except CWAC-Wakeful I have found:
Robospice: https://github.com/stephanenicolas/robospice
Android Job Queue: https://github.com/path/android-priority-jobqueue
but still I don't know, how to use these libraries to run exactly one centralized service, that whould accept jobs from any other Activity, Service, BroadcastReceiver, AlarmManager, etc, sort them by ID and run in parallel.
Please advise me what solution can be used in this case.
UPDATE: See below my own solution. I'm not sure, if it works in all possible cases. If you are aware of any problems that may arise with this, please comment.
This seems to be suited for the new JobScheduler API on Lollipop, then you will have to make a wrapper around it to implement all the features that the sdk implementation is missing.
There is a compat library if you need to implement this on versions below Lollipop.
If anybody faces the same problem, here is the solution I came up with. I used Robospice lib, because it is the most robust way of running some jobs on a Service and syncing results back to the Activity. As I did not find any ways to use this lib with WakeLocks, I extended 2 classes: SpiceManager and SpiceRequest. The new classes, WakefulSpiceManager and WakefulSpiceRequest, actually borrow CommonsWare's ideas about WakeLocks, the implementation is very similar.
WakefulSpiceManager:
public class WakefulSpiceManager extends SpiceManager {
private static final String NAME = "WakefulSpiceManager";
private static volatile PowerManager.WakeLock wakeLock;
private Context context;
public WakefulSpiceManager(Context context, Class<? extends SpiceService> spiceServiceClass) {
super(spiceServiceClass);
this.context = context;
start(context);
}
private static synchronized PowerManager.WakeLock getLock(Context context) {
if (wakeLock == null) {
PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME);
wakeLock.setReferenceCounted(true);
}
return wakeLock;
}
public <T> void execute(WakefulSpiceRequest<T> request, RequestListener<T> requestListener) {
PowerManager.WakeLock lock = getLock(context);
lock.acquire();
request.setLock(lock);
// explicitly avoid caching
super.execute(new CachedSpiceRequest<T>(request, null, ALWAYS_EXPIRED), requestListener);
}
}
WakefulSpiceRequest:
public abstract class WakefulSpiceRequest<R> extends SpiceRequest<R> {
private PowerManager.WakeLock lock;
public WakefulSpiceRequest(Class<R> clazz) {
super(clazz);
}
public void setLock(PowerManager.WakeLock lock) {
this.lock = lock;
}
#Override
public final R loadDataFromNetwork() throws Exception {
try {
return execute();
} finally {
if (lock.isHeld()) {
lock.release();
}
}
}
public abstract R execute() throws Exception;
}
So basically here we acquire the lock every time we are going to send a request from WakefulSpiceManager. After that the lock is passed to the WakefulSpiceRequest. When request finishes its work, it cleans the lock with release() method - this will happen even if the activity with WakefulSpiceManager is already destroyed.
Now we use those classes in usual Robospice's manner, with the only exception that we need to pass only WakefulSpiceRequests to execute on WakefulSpiceManager:
WakefulSpiceManager manager = new WakefulSpiceManager(context, MyService.class);
manager.execute(new WakefulSpiceRequest<MyResult>(MyResult.class) {
#Override
public MyResult execute() throws Exception {
return ...
}
}, new RequestListener<MyResult>() {
#Override
public void onRequestFailure(SpiceException e) {
...
}
#Override
public void onRequestSuccess(MyResult result) {
...
}
});
The new Workmanager will help you schedule tasks in any order you want. You can easily set constraints to the job that you want to be en-queued along with many other advantages over JobScheduler API or alarm manager. Have a look at this video for a brief intro - https://www.youtube.com/watch?v=pErTyQpA390 (WorkManager at 21:44).
EDIT: Updated my ans to show the capabilities of the new API
You will not need ids to handle the jobs with this one. You can simply enqueue the task and the rest will be handled by the API itself.
Some work case scenarios are
WorkManager.getInstance()
.beginWith(workA)
// Note: WorkManager.beginWith() returns a
// WorkContinuation object; the following calls are
// to WorkContinuation methods
.then(workB)
.then(workC)
.enqueue();
WorkManager.getInstance()
// First, run all the A tasks (in parallel):
.beginWith(workA1, workA2, workA3)
// ...when all A tasks are finished, run the single B task:
.then(workB)
// ...then run the C tasks (in any order):
.then(workC1, workC2)
.enqueue();

My App works on android 2.3.3 to android 3.1 but stops with error on 4.0 +

I just publicated yesterday my first android application.
I did not tested on android 4.0 and my friend just told me my app is crashes on his galaxy S2 (4.0.3 )
It is crashing after a few seconds in my splash screen activity, its just a few lines of code maybe you guys can check it:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen);
try
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
overridePendingTransition(0 , 0);
// thread for displaying the SplashScreen
Thread splashTread = new Thread() {
#Override
public void run() {
try {
int waited = 0;
while(_active && (waited < _splashTime)) {
sleep(100);
if(_active) {
waited += 100;
}
}
} catch(InterruptedException e) {
// do nothing
} finally {
// finish();
try
{
/*
Intent i = new Intent();
i.setClass(SplashScreen.this, MainActivity.class);
startActivity(i);
finish();
*/
}
catch(Exception e)
{
ki(e);
}
stop();
}
}
};
splashTread.start();
}
catch(Exception ex)
{
ki(ex);
}
}
#Override
public void onBackPressed() {
return;
}
//Toaster
public void ki(Exception message)
{
Toast myToast = Toast.makeText(getApplicationContext(), message.toString(), 1);
myToast.show();
}
Works verry well on Android 2.3 to 3.1 but i cant figure out whats the problem with 4.0+
Please help thank you!
Edit:
If i delete my thread everything works well. So me new question is... Whats new with threads in 4.0 ? I just ran a thread that does nothing and even i got the crash.
Thread.stop(), resume(), and suspend() no longer works with Android 4.0. The source code is below:
/**
* Requests the receiver Thread to stop and throw ThreadDeath. The Thread is
* resumed if it was suspended and awakened if it was sleeping, so that it
* can proceed to throw ThreadDeath.
*
* #deprecated because stopping a thread in this manner is unsafe and can
* leave your application and the VM in an unpredictable state.
*/
#Deprecated
public final void stop() {
stop(new ThreadDeath());
}
/**
* Throws {#code UnsupportedOperationException}.
*
* #throws NullPointerException if <code>throwable()</code> is
* <code>null</code>
* #deprecated because stopping a thread in this manner is unsafe and can
* leave your application and the VM in an unpredictable state.
*/
#Deprecated
public final synchronized void stop(Throwable throwable) {
throw new UnsupportedOperationException();
}
A lot of application crashes on Android 4.0 because of this. This is not Google's fault; from years ago Java SDK has discouraged using stop() on a thread.
Quote from changelog:
Commit: a7ef55258ac71153487357b861c7639d627df82f [a7ef552]
Author: Elliott Hughes <enh#google.com>
Date: 2011-02-23 6:47:35 GMT+08:00
Simplify internal libcore logging.
Expose LOGE and friends for use from Java. This is handy because it lets me use
printf debugging even when I've broken String or CharsetEncoder or something
equally critical. It also lets us remove internal use of java.util.logging,
which is slow and ugly.
I've also changed Thread.suspend/resume/stop to actually throw
UnsupportedOperationException rather than just logging one and otherwise
doing nothing.
Bug: 3477960
Change-Id: I0c3f804b1a978bf9911cb4a9bfd90b2466f8798f
As #Yuku says, Thread.stop() isn't somehow broken in ICS it's specifically changed to throw an exception as it's unsafe:
http://developer.android.com/reference/java/lang/Thread.html#stop()
public final synchronized void stop (Throwable throwable)
Since: API Level 1 This method is deprecated. because stopping a
thread in this manner is unsafe and can leave your application and the
VM in an unpredictable state.
Throws UnsupportedOperationException.
Throws NullPointerException if throwable() is null
If you want you're thread to be forcefully stopped instead use threadName.interrupt() while external to your thread. Program in a natual end to you're threads lifecycle so that it stops naturally when it's task is complete.
In your example you can simply delete the command stop() since the thread will naturally cease execution at the end of it's run() method.
EDIT finish() is a call to your Activity to finish, not your Thread. In the above example the Thread would exit naturally anyway but please don't be confused with stopping a Thread and finishing an Activity as they are vastly different things.
I had the same issue using stop() on Android 4.0. Try using finish() instead, that solved my problem.
I guess that stop() is no longer working on ICS.
My tutorial at droidnova.com is not updated to work on ICS, sorry, hadn't time for that. Today I would use a handler instead of the separate thread. Much easier to use and more robust.

Categories

Resources