how to open new activity from a thread with an handler - java

at the beginning every thing worked well, but i changed things and now the applcation crash when i open the new activity from a thread (not the UI thread).
the application only crash on my phone after installation, in debug mode it work well for some reason i can't understand.
this is my handler:
handler = new Handler(Looper.getMainLooper());
// --- thread work function ---
public void OnLoseActivity()
{
handler.post(new Runnable() {
#Override
public void run() {
Intent myActivity= new Intent(mainActivity.this, newActivity.class);
startActivity(myActivity);
}
});
}
something that i am doing wrong?
need to handle other issues before closing this first activity?
thanks
Update:
the reason i open an activity from a thread is that the thread checking for something in a loop, if it happand the activity shuold open.
I am not used to work with handlers, explain to me if im doing newb things please.
as i wrote, nothing special in the logcat because on debug it's working fine

If you're running this in an Activity, try this. Put your Intent in a method and call the method in your Runnable.
void startMyActivity()
{
Intent myActivity= new Intent(mainActivity.this, newActivity.class);
startActivity(myActivity);
}
and change your Runnable:
new Handler().post(new Runnable() {
#Override
public void run() {
startMyActivity();
}
});

Related

Restart Activity on uncaughtException

in the onCreate method of an Activity, I'm running this :
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
Intent intent = getIntent();
finish();
startActivity(intent);
}
});
What I am trying to do is, when in this activity, I would like to restart it and clear previous intents, with these lines of code, I end up having a blank screen and the app running in the background, either way I have to restart it or kill it from the multitasking screen and this is not really user friendly. Any ideas? Thanks!
Edit : Is it also possible to build an alert dialog in here as well and display some message? And perhaps on OK press, the redirect will happen
For future reference, this did the trick for me :
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
Intent crashedIntent = new Intent(MainDrawer.this, MainDrawer.class);
crashedIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
crashedIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(crashedIntent);
System.exit(0);
}
});

Android Thread Allocation - growing heap?

Hi everyone out there,
i am developing an android application against API 7 at the moment in which i use an activity which need to be restarted. Lets say my activity looks like this:
public class AllocActivity extends Activity implements OnClickListener{
Button but;
private Handler hand = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_alloc);
but = (Button) findViewById(R.id.button);
but.setText("RELOAD");
but.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0){
Intent intent = getIntent();
startActivity(intent);
finish();
}
});
}
#Override
protected void onDestroy(){
super.onDestroy();
System.gc();
}
/****** THREADS AND RUNNABLES ******/
final Runnable fullAnim = new Thread(new Runnable(){
#Override
public void run(){
try{
hand.post(anim1);
Thread.sleep(2000);
hand.post(anim2);
Thread.sleep(1000);
// and so on
}catch(InterruptedException ie){ie.printStackTrace();}
}
});
final Runnable anim1 = new Runnable() {
#Override
public void run(){
// non-static method findViewById
ImageView sky = (ImageView)findViewById(R.id.sky);
}
};
}
The problem is that the gc doesnt seem to free the fullAnim thread so that the heap is growing by ~100K at every restart - till it slows down and crashes. Declaring fullAnim as static does solve this problem - but as i use non static references this doesnt work out for me.
So at this point i am kindof lost - and i hope u can advice me where to go next. Is there something i might be doing wrong or is there a tool i can use to manage threads to drop and free heap after restart.
kindly regards
UPDATE
thanks to everyone who answered - helped alot. using TimerTask did the trick in the end. i did the following change:
/****** THREADS AND RUNNABLES ******/
final TimerTask fullAnim = new TimerTask(){
#Override
public void run(){
try{
hand.post(anim1);
Thread.sleep(2000);
hand.post(anim2);
Thread.sleep(1000);
// and so on
}catch(InterruptedException ie){ie.printStackTrace();}
}
};
as the activity was more than 6k loc long this was a pretty decent solution without facing bigger impacts. KUDOS!
i dont use a Timer to shedule the task - dont know if its bad practice but
the animation is called like this:
Thread t = new Thread(fullAnim);
t.start();
A running Thread is never garbage collected.
A Thread is not stopped automatically if your Activity stops or is destroyed. It could run forever.
Every non-static inner class keeps a reference to the enclosing instance. E.g. hand.post(anim1); works inside that inner class because it has an implicit reference to AllocActivity.this.
So what you effectively do is to keep a reference to your Activity alive for longer than it is supposed to be alive, i.e. until after onDestroy.
Make sure to stop threads manually if you don't want them anymore.
Because final variable have low priority for GC. So you need to explicitly release the runneable objects in onPause() method because there is not ensurence onDestory() will call immediate after finish() call .
#Override
protected void onPause(){
super.onPause();
//cancel timer to stop animations
if(t!=null){
t.cancel();
}
System.gc();
}
UPDATE
use timer to achieve this
boolean isFirstAnim=true;
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
if(isFirstAnim){
// play your first animation at every
}else{
// play your second animation at every
}
}
}, 0, 3000);
What happens when all activities of an application finishes?
"When you call finish() this doesn't mean the Activity instance is
garbage collected. You're telling Android you want to close the
Activity (do not show it anymore). It will still be present until
Android decides to kill the process (and thus terminate the DVM) or
the instance is garbage-collected."
You need to implement your own stop method to stop the running thread, you can make a call to it in onDestroy
refer this Stopping a runnable
Alternatively
you can perform your operation in an asynctask and use onProgressUpdate() to publish progress on UI thread and use cancel(true) in combination with check in doInBackground() whether cancel has been called to stop the task.

Is it a bad practice use Thread.sleep(Milliseconds) for wait a bit before start another activity?

I'm making a SplashScreen for an app ... When the app starts, it start LoadingActivity ... sleep for 3 seconds, finish(); and then starts the MainActivity. Splash serves to update the database. If the database is already updated, I want the splash still for 3 seconds anyway.
I am using the following code:
protected void onPostExecute(Void result) {
super.onPostExecute(result);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
Intent intent = new Intent(LoadingActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
}
Is it a bad pratice? and why? The app is running nicelly in AVD.
Sleeping on the UI thread is always a bad idea. In this case you are in an onPostExecute, which is on the UI thread.
Throw your sleep into the doInBackground method of your AsyncTask instead, and you won't get any ANR's there (Android not responding).
Users don't like waiting for splash screens, so it is better not to wait at all. But sometimes the splash screen is required (ie due to contracts).
Yes it is bad practice, onPostExecute() is called on UI thread so basically you are blocking your UI thread for 3 whole seconds. I suspect you want to show a splash screen. You can instead do it like this.
new Handler().postDelayed(new Runnable(){
#Override
public void run(){
Intent intent = new Intent(LoadingActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
},3000);
or if you want to stick with AsyncTask then override doInBackground() and sleep in it and launch your Activity in onPostExecute() normally.
If this is is at the very start of the Programm you could do a while Loop that runns until System.currentTimeMillis() is higher than 3000 than it was at the Start of the program.

Android thread confusion

I have written a function to create a splash screen with a 5 second timeout for my app.
The code works fine, but when the timeout reaches zero and I want to redirect to my main activity, the app crashes with the following error:
Only the original thread that created a view hierarchy can touch its views.
So I looked around a bit and someone suggested nesting this inside my function. It seems like a good Idea, but now methods like sleep / stop won't work.
My code is below, I can provide more / explain more in details if it isn't clear enough just let me know. Thanks for the help.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showSplashScreen();
}
protected boolean _active = true;
protected int _splashTime = 5000; // Splash screen is 5 seconds
public void showSplashScreen() {
setContentView(R.layout.splash_layout);
// Thread splashThread = new Thread() {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
int waited = 0;
while (_active && (waited < _splashTime)) {
Thread.sleep(100);
if (_active) {
waited += 100;
}
}
} catch (InterruptedException e) {
// do nothing
} finally {
showApplication();
}
}
});
}
Probably not what you want to hear, but you should never put a splash screen on your mobile app. With the exception of games, when people use a mobile app they want to get in, do what ever it is they need to do, and get out. If you make that process take longer, people are just going to get frustrated with you app. You should probably reconsider just not using a splash screen.
This will perform sleep on the UI thread. That's never a good idea.
Why not something like this?
new Handler().postDelayed(new Runnable() {
public void run() {
// start application ...
}
}, _splashTime);
But this answer has a good point. Displaying a splash screen for 5 seconds can be very annoying.
I believe you want AsyncTask for this. The method called on completion of the task will be called on your UI thread, making modifying UI elements much easier.
Use a Handler to post an event to the UI thread that will remove the splash.
Code should be something like...
splash.show()
new Handler().postDelayed(
new Runnable() {
void run() {
splash.remove();
},
delayTime);
I suggest you to make new activity for your spalsh screen, show it in a regular way (with startActivityForResult) and place in it such code (in it, not in your main activity):
new Handler().postDelayed( new Runnable()
{
public void run()
{ finish(); }
}, 5000 );
Also you can handle in this new activity click events for giving opportunity to user to close it faster, tapping on it.

Using global exception handling with "setUncaughtExceptionHandler" and "Toast"

I am trying to create a simple exception handler which will help me debug the application. Right now, when I have an exception I am forced to connect with Eclipse debugger merely to see the exception details.
To avoid that I've used setUncaughtExceptionHandler to handle any unhandled exception and display a Toast on the exception. Unfortunately, that doesn't work.
public class TicTacToe extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
Toast.makeText(TicTacToe.this, "TOAST", Toast.LENGTH_LONG).show();
}
});
setContentView(R.layout.main);
Button continueButton = (Button) findViewById(R.id.cell01);
continueButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int i = 5;
i = 5 / 0;
Toast.makeText(TicTacToe.this, "BUTTON", Toast.LENGTH_LONG).show();
}
});
}
}
Essentially I made a form with a single button, pressing on which, it would throw a devision-by-zero exception. However, pressing the button doesn't cause the global toast handler to show. Instead, the button stays orange (pressed) and nothing happens.
Needless to say, if I comment out i = 5 / 0; I see the toast that says that a button was pressed.
Two questions:
1) Why isn't the toast showing in the UncaughtExceptionHandler body? How do cause it to show?
2) Is there an alternative/better way for global exception handling? I guess I could install aLogCat on the android simulator and simply log the uncaught exception, it seems, however, less comfortable - I will need to be switching applications just to see exception details.
Thanks!
It is possible. You need to do it inside another thread
Then it should be like this
Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
new Thread() {
#Override
public void run() {
Looper.prepare();
Toast.makeText(TicTacToe.this, "TOAST", toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
}
});
You're not seeing anything because the exception happened on your UI thread and the stack unrolled all the way. So there is no more Looper and there is no support there that is used to display the Toast. If you want to display the exception information on screen you'll most likely need to start another Activity in another process.
There is also a problem with your UncaughtExceptionHandler. You really should keep a reference to the old one and call it at the end of uncaughtException this allows the system to display the Force Close button.
I know it's an old question but I hope I can save someone from frustration and wasting time.
Qberticus is right, you can't start an Activity on the same process, but you can kill the current process and have android run it in a new one:
Intent intent = new Intent(myContext, AnotherActivity.class);
intent.putExtra("error", errorReport.toString());
myContext.startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
refer to this page for an awesome working example:

Categories