How to simulate client-side delay on Android without hanging the UI? - java

I have an Androd application that talks to a back-end web service. As part of the testing, I need to simulate different lengths of client-side delay when a submit button is pressed.
Right now, I am using a Thread.sleep() in my OnClickListener for my submit button, but sleeping the UI thread like this has the unintended consequence of causing the app to appear to "freeze" completely - the button stays highlighted until the thread wakes up and my ProgressBar is likewise completely frozen. Here is my code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);
pBar = (ProgressBar) findViewById(R.id.progressBar1);
pBar.setVisibility(View.INVISIBLE);
Button submitButton = (Button) findViewById(R.id.btnSubmit);
submitButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
pBar.setVisibility(View.VISIBLE);
try {
Thread.sleep(3000); //eventually this delay will be random
//right now it obviously hangs the UI
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
performMyAppSpecificWorkHere();
pBar.setVisibility(View.INVISIBLE);
CheckoutActivity.this.finish();
}
});
}
I'm looking for ways I could simulate a delay without hanging the entire UI. Any ideas are welcome. Thanks!
edit
Some clarification here! Part of what I need to do is make simulate a delay and allow the user interface to handle it cleanly (which is what's NOT happening now).
ie...if there is a delay on either the client or the web service, the client should handle it by letting the spinner spin while it waits. The ability to simulate a back-end delay is already done and that works the way I want it to, but I want to simulate a delay on the client without hanging the UI thread.

here we go:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);
pBar = (ProgressBar) findViewById(R.id.progressBar1);
pBar.setVisibility(View.INVISIBLE);
Button submitButton = (Button) findViewById(R.id.btnSubmit);
submitButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Thread t=new Thread(new Runnable(){
#Override
public void run(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
performMyAppSpecificWorkHere();
runOnUiThread(new Runnable() {
#Override
public void run() {
pBar.setVisibility(View.INVISIBLE);
CheckoutActivity.this.finish();
}
}
}
});
pBar.setVisibility(View.VISIBLE);
t.start();
}
});
}
So, you are starting a new thread in the onClick event. This new thread should do the application work after sleeping for 3 seconds. After that, you want to update some ui objects, and you can not do that from inside a thread that isn't the UI Thread. That's why there is a runOnUiThread(..) after performing the work. Hope it helps!

First of all, don't block the main thread (the ui-thread), or else the gui will be freezed! Instead, use AsyncTask, where you put Thread.sleep(3000) inside doInBackground(), and then do whatever you want inside onPostExecute() (onPostExecute() is running in the main thread). Check my last answer on related question.

I think you should clarify here, you want to simulate server side delays and not the client side delay. You should put the sleep code in your server side code and not the client side code.
If it is not so, you can use asyncTask and execute the application code. You can put the sleep code inside it to simulate a client side delay.

Related

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.

Sleep() in Android Java

I am following this tutorial to have a loading screen in my program. The tutorial says my activity should Sleep() using the Sleep() command, however it does not recognize Sleep() as a function and provides me with an error, asking if I would like to create a method called Sleep().
Here is the code sample:
public class LoadingScreenActivity extends Activity {
//Introduce an delay
private final int WAIT_TIME = 2500;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
//Simulating a long running task
this.Sleep(1000);
System.out.println("Going to Profile Data");
/* Create an Intent that will start the ProfileData-Activity. */
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
}, WAIT_TIME);
}
}
You can use one of the folllowing methods:
Thread.sleep(timeInMills);
or
SystemClock.sleep(timeInMills);
SystemClock.sleep(milliseconds) is a utility function very similar to Thread.sleep(milliseconds), but it ignores InterruptedException. Use this function for delays if you do not use Thread.interrupt(), as it will preserve the interrupted state of the thread.
The function is Thread.sleep(long).
Note, however, that you should not perform a sleep on the UI thread.
The code you posted is horrible. Please don't use that on an actual device. You will get an "Application Not Responding" error if you run something similar to this.
If you're using Handlers, keep in mind that a Handler is created on the thread where it runs. So calling new Handler().post(... on the UI thread will execute the runnable on the UI thread, including this "long running operation". The advantage is that you can create a Handler to the UI Thread which you can use later, as shown below.
To put the long running operation into a background thread, you need to create a Thread around the runnable, as shown below. Now if you want to update the UI once the long running operation is complete, you need to post that to the UI Thread, using a Handler.
Note that this functionality is a perfect fit for an AsyncTask which will make this look a lot cleaner than the pattern below. However, I included this to show how Handlers, Threads and Runnables relate.
public class LoadingScreenActivity extends Activity {
//Introduce a delay
private final int WAIT_TIME = 2500;
private Handler uiHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHandler = new Handler(); // anything posted to this handler will run on the UI Thread
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
Runnable onUi = new Runnable() {
#Override
public void run() {
// this will run on the main UI thread
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
};
Runnable background = new Runnable() {
#Override
public void run() {
// This is the delay
Thread.Sleep( WAIT_TIME );
// This will run on a background thread
//Simulating a long running task
Thread.Sleep(1000);
System.out.println("Going to Profile Data");
uiHandler.post( onUi );
}
};
new Thread( background ).start();
}
use Thread.sleep(1000);
1000 is the number of milliseconds that the program will pause.
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
Keep in mind: Using this code is not recommended, because it is a delay of time but without control and may need more or less time.

Using the java timer

Until now I have been using the Timer that's in javax.swing.timer - all I had to do was to choose the speed and have a method with a specific name that executes what I want the timer to do every time.
I have now started programming an Android application recently and I have faced a couple of problems...
It wouldn't let me use or import javax.swing.timer
I tried using java.util.timer but I couldnt figure out how it works
All I want my timer for is so I can display my logo for 3 seconds and then proceed to the main menu - even if there is an easier solution for this, I'd still like to know how to use the timer
For the person who told me to try using a thread - here is my code - it doesnt paint the first screen at all, it just stays blank for 3 seconds then moves on to the next line of code...
public class logo extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
setContentView(R.layout.logoview);
Thread.sleep(3000);
}
catch (InterruptedException e){
e.printStackTrace();
}
setContentView(R.layout.main);
}
public void startup (View view){
Intent intent0 = new Intent (this,ExpiramantingActivity.class);
startActivity(intent0);}
}
}
in onCreate() function of your SplashActivity class, schedule a handler to display your main menu activity after 3 seconds. this should be done after setContentView(R.layout.splashscreen);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(SplashActivity.this,
YourMainMenuActivity.class));
finish();
}
}, 3000);
I believe that what you are trying to do is similar to the exhibition Splash Screen. If so, please check this Oracle tutorial.
try this:
// logo
Thread timer = new Thread(){
public void run(){
try{
sleep(3000);
} catch (InterruptedException e){
e.printStackTrace();
}
};
};
timer.start();
//next code
Maybe you can use a Thread? I think it's the simplest way to do what you want:
Where you display your logo:
try {
//show your logo here
Thread.sleep(3000); //3 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
Surrounding the code in a try/catch block is very important, because of the posibility of an Exception.

Using a progressdialog and handler

I'm working on an app that connect to a webpage to get some content. I want to show a progressdialog, but I think I'm doing something wrong.
This is my code:
final ProgressDialog myProgressDialog = ProgressDialog.show(WhoisBeyondActivity.this, "Wait...", "Fetching data...", true);
Handler handler=new Handler();
handler.post(new Runnable()
{
public void run()
{
try {
// code to execute
Thread.sleep(2000);
} catch (Exception e) {
}
myProgressDialog.dismiss();
}
});
The problem is that the progressdialog is only shown one second at the end of the operation I want to make. I think the progressdialog is only executing when I execute the dismiss() because it appears and dissapears quickly. Is like the progressdialog appears only to dissapear ... help me please!!! I have read a lot of tutorials, and I have try a lot of option, like THREAD instead of HANDLER, but it is not usefull for me, because I have to edit UI.
There's an excellent example and tutorial here:
http://www.helloandroid.com/tutorials/using-threads-and-progressdialog
That's what I used the first time I did a threaded dialog in Android, and I bookmarked it. Hopefully it helps.
The reason you are getting the described behaviour is that the post method will just execute the passed in runnable against the thread to which the Handler is attached. In your case this is the UI thread.
You are calling ProgressDialog.show(), which is asynchronous. This does not actually show the dialog as soon as the method returns, rather you have just requested that the UI display a dialog. You then immediately post a thread that sleeps for 2 seconds, which is added to the UI queue and blocks the UI from performing the dialog show. The UI then wakes from your sleep, shows the dialog then is dismissed.
You should perform any network operation in either a new Thread or in an AsyncTask. Have a look at these links for more details:
AsyncTask
Painless threading
Threading
Designing for responsiveness
Thread documentation
Handler documentation
You don't want to use a separate thread per-say. What you really want is an AsynTask. This will allow you to create the progress dialog and do the background processing right there in the task. Simple to write and easier to implement. If your refer to the link, what you need is actually really similar to your question. With a little tweaking, it should work just fine for you.
public class HelloActivity extends Activity {
protected static final String TAG = "HelloActivity";
ProgressDialog myProgressDialog;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//
showDialog(1);
final Handler handler=new Handler(){
#Override
public void handleMessage(Message msg) {
//update UI here depending on what message is received.
switch(msg.what){
case 0:
myProgressDialog.dismiss();
}
super.handleMessage(msg);
}
};
Thread t = new Thread(){
public void run(){
try {
// code to execute
Thread.sleep(5000);
} catch (Exception e) {
}
handler.sendEmptyMessage(0);//nothing to send
}
};
t.start();
}
#Override
protected Dialog onCreateDialog(int id) {
myProgressDialog = ProgressDialog.show(HelloActivity.this, "Wait...", "Fetching data...", true);
return myProgressDialog;
}
}

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.

Categories