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.
Related
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.
I'm developing an Android app that has to update it's UI depending on receiving and processing some server responses, I'm using runOnUiThread for that. I have like five activities in that app, all is working very well but one requires me to relaunch the Activity(like going to another one and then returning to it) or interacting with it in order to that update takes place, and that is the way i'm using with all the Activities including the infected one:
runOnUiThread(new Runnable() {
public void run() {
try {
response_received(response);
} catch (Exception e) {
e.printStackTrace(); // never catch any Exceptions
}
}
});
private static void response_received(JSONObject response) throws Exception{
try {
int volume_setted = response.getInt(volume);
Normal_Activity.volume_value.setText(String.valueOf(volume_setted)); // the Volume TextView updated efficiently
Infected_Activity.volume_value.setText(String.valueOf(volume_setted)); // has the problem mentioned above
} catch (JSONException ex) {
}
}
I'm pretty sure the problem is not in the TextView as all the Activity UI has this problem but i just posted an example.
Do not directly set values in a Activity from another Activity. If you want to pass data to Another activity always use Intents. check the below link
pass data from intent to an other intent
If you want to start another activity and get result back check the below link
http://developer.android.com/training/basics/intents/result.html
I am developing an app with quite a few threads, it often crashes so far, whenever I load the new version from eclipse, it seems to create a new process.
I cannot seem to find a way to kill the old processes, they do not apear in the running apps.
I can see that I have multiple processes related to my app in the process list ("ps" command).
Is there a way to make sure the app process actually dies on crash?
have you tried this android.os.Process.killProcess(android.os.Process.myPid()); it can kill your process
You can kill your app's process by:
System.exit(1);
It order to know when your app crashes (exception that's not being caught) you'll need to define:
Thread.setDefaultUncaughtExceptionHandler(new CustomUncaughtExceptionHandler());
In your main Thread.
CustomUncaughtExceptionHandler is:
public class CustomUncaughtExceptionHandler implements UncaughtExceptionHandler
{
private UncaughtExceptionHandler defaultUEH;
public CustomUncaughtExceptionHandler()
{
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
}
public void uncaughtException(Thread t, Throwable e)
{
// Put system.exit here
if (defaultUEH != null)
{
defaultUEH.uncaughtException(t, e);
}
else
{
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
defaultUEH.uncaughtException(t, e);
}
}
}
I have the following function call from a thread:
Thread Move = new Thread(){
public void run()
{
while(ButtonDown){
UpdateValues();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Move.start();
Will Android delete the thread when the while-loop breaks, or do I have to delete it in some way?
There are two concepts here. One is the thread itself, the thing running in the processor, that has stack memory. The other is the Thread object, which is basically a control panel to access the thread.
The thread has stack memory which is released when the thread dies (run() completes or an exception is thrown, basically). However, the Thread java object stays around until there is no longer a reference to it.
So, let's say you had this:
this.myThread = new Thread(){
public void run()
{
int[] takeUpSomeMemory = new int[10000];
while(ButtonDown){
UpdateValues();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
this.myThread.start();
So you have an instance variable myThread which holds a reference to a Thread you create. When the start method is called, your thread is called and it allocates quite a bit of memory for the variable takeUpSomeMemory. Once the run() method dies by completing execution or throwing an exception the memory for takeUpSomeMemory is garbage collected. The memory for this.myThread is retained until the instanceVariable is set to nil or the object of the enclosing class is garbage collected.
When you return from the thread, you have essentially stopped it, so no, you don't need to do anything specific to delete the thread. Please keep in mind that this is not a good use case for threads in Android. If you are updating the UI from a non-UI thread you will most likely get the framework complaining at you. Instead, you should read a few tutorials on AsyncTask and move to that model, as it will let you update the UI.
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.