I setted up simple application with 2 activities. I had problem in first activity. It is used just for displaing logo for 3 seconds and then launching second activity. Problem is that it doesn't load the layout, it waits 3 seconds and then load second activity. The code is here:
public class StartActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_screen);
final Intent myAct = new Intent(this, MyActivity.class);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
startActivity(myAct);
finish();
}
}
I was able to fix this problem by creating another thread and executing waiting there. Fixed code is here:
new Thread(){
public void run(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
startActivity(myAct);
finish();
}
}.start();
So i actually fixed the problem. I just want to know why it works the second way but it doesnt work by first way becouse i don't understand it.
In the first case, you are telling the UI Thread to sleep, preventing it to draw the layout. When it finishes the sleep process, it immediately starts the next Activity. That is why you do not see the first Activity layout being shown. This approach is not recommended at all as during the sleep time, your application is not responsive to any user actions. You are recommended to use an AsyncTask or a new Thread or a Handler, using postDelayed() method but never cause the UIThread to stop doing its job (drawing and handling UI events).
In the second case, you are making the sleep() in a new Thread, not the UIThread. So, what happens is that the UI Thread is never interrupted and is allowed to draw the entire layout. At the same time, the sleep time is respected as well. Once the sleep() ends, your new Activity starts.
First method makes the UI thread sleep .This result in stopping of all the functioning and UI interaction of the activity.
The second method uses another thread .Since it's the other thread which sleeps all the UI parts of the main UI thread works fine and the code works as intended.
Actually your approach is also wrong / bad practice.
Starting new activity and finishing current should be done on main thread.
Also try to avoid final objects initialization, they may stack in memory.
Here is one of correct approaches (postDelayed() will be perform on MainThread):
public class StartActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_screen);
View view = findViewById(R.id.any_view_from_start_screen_layout);
view.postDelayed(new Runnable(){
public void run(){
startNewActivityAndCloseCurrent();
},3000);
}
private void startNewActivityAndCloseCurrent(){
Intent myAct = new Intent(this, MyActivity.class);
startActivity(myAct);
finish();
}
}
Related
I have a method in which I want a delay of a second, and while the delay is running there should be a loading animation (ProgressBar).
Right now, when the method is now running the loading animation is not appearing. If I do not call the Timeout it does appear, and when I do not make it invisible after, it shows up after the timeout.
How do I show the loading animation while the timeout is running? I have a similar problem trying to do with with Thread.sleep(1000).
public void firstMethod(){
ProgressBar pgLoading = (ProgressBar) findViewById(R.id.pgLoading);
pgLoading.setVisibility(VISIBLE);
try {
TimeUnit.SECONDS.sleep(1);
}catch(InterruptionException ex){
ex.printStackTrace();
}
pgLoading.setVisibility(INVISIBLE);
}
By calling the sleep method you are making the UI thread sleep for 1 second during that time nothing will happen on UI Thread hence you do not see the ProgressBar. You should instead use a TimerTask to wait for this one second and then close the ProgressBar.
Checkout this link on how to use TimerTask.
Main thread can't be blocked. That will cause the entire rendering to stop. That's why you only see the result after that timeout.
These kind of operations shoud be handled in other threads. If you are using Java you can use Runnables but you should consider moving to Kotlin to use coroutines.
E.G:
pgLoading.setVisibility(VISIBLE);
new Thread() {
public void run() {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
pgLoading.setVisibility(INVISIBLE);
}
});
}
}
}.start();
This is happening because the current thread is being paused.To avoid this put your delay/long process in a different thread.For example:
public void firstMethod(){
ProgressBar pgLoading = (ProgressBar) findViewById(R.id.pgLoading);
pgLoading.setVisibility(View.VISIBLE);
new Thread(()->{
// Do all your long process here
try {
TimeUnit.SECONDS.sleep(1);
}catch( InterruptedException ex){
ex.printStackTrace();
}
runOnUiThread(() -> pgLoading.setVisibility(View.INVISIBLE));
}).start();
}
I'm having an issue with an acitivity for an android app, to make it simple I let there be three activities : the main M, the one that answers A and the one I start C.
So M starts A using startActivityOnResult, then A sends result to M and from there M starts S.
But for some reason, the layout of S doesn't update until the main method I call from there is finished (and when that method is finished the activity goes back to M anyway, so basically I only see the layout if I make the activity S not give the result and stand there doing nothing).
Here is some of the code :
In M starting S :
Intent intent = new Intent(MainActivity.this, getCamFind.class);
intent.putExtra("path", mCurrentPhotoPath);
startActivityForResult(intent, CAMFIND_REQUEST_CODE);
In S :
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_getcamfind);
receivedIntent = getIntent();
Log.d(TAG, "Received string : " + receivedIntent.getStringExtra("path"));
}
public void onStart(){
super.onStart();
try {
postCamResult(receivedIntent.getStringExtra("path"));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
So here the main method I was talking about is postCamResult, it basically connects to a server using retrofit. At the end of this method is where I would usually put the few lines to send back the result intent. The problem being the layout waits for this method to finish for some reason ? so if I don't send the result intent, it will, after doing all the server related stuff, finally print my layout, but you know, I'd like my layout to appear as soon as I open the activity!
Thank you in advance !
The Android documentation for the Activity lifecycle states that the visible lifetime of an Activity is between onStart() and onStop(), so the layout you set will be rendered after the onStart method is done.
If you put your postCamResult() inside onResume() you should be fine.
Still connecting to a server on the UI Thread is a bad idea, you should start a seperate thread for that, otherwise you might get an anr.
I've been playing around with an app I created.
Activity A(1st Activity) has a button that executes an AsyncTask. This AsyncTask's doInBackground() performs calculations on selected values in Activity A, and its onPostExecute() starts Activity B.
I click the button, then before Activity B can be started I press back to destroy Activity A.
The app closes, then relaunches with Activity B populated with calculations from my AsyncTask.
this awesome blog explains memory leaks with Threads when the screen is rotated, and I'm applying those lessons here with my AsyncTask and back button press. However, I'm still a little confused.
Pressing back on an Activity destroys it.
My asynctask is running on an activity that was destroyed, should throw a NPE since it's accessing list elements inside that activity.
But it didn't. What does destroyed really mean then? I thought it meant that the Activity A reference and its view hierarchy would be set to null to allow the garbage collector to sweep it up sometime and recycle the memory. The blog states it didn't, hence the memory leak.
So wait, Activity A didn't get destroyed? But I saw it disappear...
This is a conceptual question rather than a code question so far, but as requested:
private class MyAsyncTask extends AsyncTask<ArrayList<Train>, Void, Void> {
protected void onPreExecute() {
// Runs on the UI thread before doInBackground
spinWait.setVisibility(ProgressBar.VISIBLE);
waitMsg.setText("Calculating Schedules....");
spinWait.bringToFront();
waitMsg.bringToFront();
}
#Override
protected Void doInBackground(ArrayList<Train>... lolTrains) {
try {
calcSchedules(lolTrains[0]);
} catch (Exception e) {
Log.d("DEBUG", "Calculating schedules failed, " + e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(Void v) {
// This method is executed in the UIThread
spinWait.setVisibility(View.GONE);
waitMsg.setVisibility(View.GONE);
// if schedules is empty, show error dialog
if (schedules.size() == 0) {
// show msg, etc
} else {
Intent i = new Intent(getBaseContext(), ResultsActivity.class);
i.putExtra("results", schedules);
startActivity(i);
}
}
}
public void MethodInActivityA(View v) {
new MyAsyncTask().execute(memberVarInActivityA);
}
When you destroyed your activity, you did not destroy you AsyncTask (which is basically kind of a Thread), to do that try
asyncTask.cancel(true);
on your onDestroy(); method
hope this helps
On your onPostExecute(), When start new activity call finsih() followed by startActivity(i). This finish() internally call onDestroy. Here you need to clear Asynctask manually because Asynctask is inner class of your Activity. Even activity was destroyed this inner class holds the reference of activity. You need manually clear the reference by asyncTask.cancel().
In the Android app I'm writing I want my activity to display my company's logo and then launch a new activity three seconds after. I have the layout done and the graphic in the right place but I don't know how to make the timer.
What is the simplest, shortest way to create the three second timer?
Thank you very much in advance for all of the responses I receive.
Laurence Dawson's answer is fine, but (1) go straight to the Handler section, and (2) for your application you want postDelayed instead of postAtTime.
Actually there is a nearby answer very close to what you're looking for, except that instead of calling start, you want to instantiate a Handler and use postDelayed to schedule your Runnable 3 seconds later.
Heres a great page on the Android developer docs. They create a simple timer extending the "TimerTask".
here you go ... just tru threading .. thread will let ur activity sleep after some time and then start an intent .. and u must finish() activity when it is in pause mode :D see this
Thread t = new Thread()
{
public void run()
{
try{
sleep(3000);
}catch(InterruptedException ie)
{
ie.printStackTrace();
}finally
{
Intent i = new Intent(getApplicationContext(), login.class);
startActivity(i);
}
}
}; t.start();
}
public void onPause()
{
super.onPause();
finish();
}
I'm having trouble getting the GPS's onLocationChanged to run on a different thread. I understand how to manage UI thread when I'm calling a function but with the GPS, I don't actively call the function.
My intent is to have a light flash every time the GPS receives a reading. I have put this function in a Runnable. I passed this function to a class that implements LocationListener. Then in the main class, I started a new thread that calls requestLocationUpdates. I was hoping that onLocationChanged of the LocationListener would run in a different thread, post to the callback and make the necessary UI effects in the UI thread. Unfortunately, the program crashes every time it tries to call requestLocationUpdates. What's the proper way of doing it?
Right now it looks something like this
Main class:
final Runnable changeLight = new Runnable(){
public void run(){
// do stuff
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.capture);
status = (ImageView) findViewById(R.id.status);
database = new DatabaseManager(this);
new Thread(){
public void run(){
location = (LocationManager) getSystemService(LOCATION_SERVICE);
listener = new GPSManager(database, changeLight, light, status);
location.requestLocationUpdates("gps", 10000L, 0, listener);
}
}.start();
}
LocationListener class:
public void onLocationChanged(Location location) {
if (location.getAccuracy() <= 32.0){
light = lightColors.Green;
status.post(callback);
database.insertData(location);
}
else{
light = lightColors.Yellow;
status.post(callback);
}
}
The exception says Can't create handler inside thread that has not called Looper.prepare()
The thread where you call location.requestLocationUpdates must have a Looper ( see here ).
You can use HandlerThread instead of Thread.
I was running in to the same problem. The solution turns out to be that the new thread where you want to receive Location updates from the Location Manager has to be a Looper thread. To do so, all you should do is add following lines in the run() function of your thread.
Looper.prepare();
Looper.loop();
Could your problems be arising from improper synchronization of the main thread? Do you get any exceptions before the app crashes? Can you post an sscce.org compliant example?
In general when you're processing asynchronous events on the GUI you should have proper synchronization: http://developer.android.com/resources/articles/painless-threading.html