**I configured a simple single TextView layout (see below after the code) to change the display changing from 10 up to 20. What I see is "20" being displayed. My code is as follows. Want to know why only the last number ("20") is displayed omitting the intermediate ones(10 thru 19))
package com.example.test;
import android.R.string;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
import android.widget.Toast;
public class TestActivity extends Activity {
public TextView mytv;
public Toast mtoast;
#Override
protected void onCreate(Bundle savedInstanceState) {
int i = 10;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mytv = (TextView) findViewById(R.id.myhw);
mtoast = Toast.makeText(this, String.valueOf(i), Toast.LENGTH_LONG);
while (i++ < 20) {
mtoast.setText(String.valueOf(i));
mtoast.show();
mytv.setText(String.valueOf(i));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.test, menu);
return true;
}
}
The relevant layout is as follows.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".TestActivity" >
<TextView
android:id="#+id/myhw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
</RelativeLayout>
because the view is not shown until onResume call and after that the activity is displayed, all you are doing is changing the view content in onCreate method, after onCreate activity goes to onStart and onResume so when onCreate finishes the textView value is 20 and after onResume it sets the value to 20.
for more information look at activity life cycle at :
http://developer.android.com/reference/android/app/Activity.html
You shouldn't sleep the UI thread in the first place.
What you probably want to do is to use another thread, let it sleeps for a couple of seconds and, each time you update the UI, use the UI (main) thread. You can do it in several ways, but the simples probably is using an AsyncTask, as:
public class MyActivity extends Activity {
public TextView mytv;
public Toast mtoast;
private int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
i = 10;
mytv = (TextView) findViewById(R.id.myhw);
mtoast = Toast.makeText(this, String.valueOf(i), Toast.LENGTH_LONG);
new AsyncTask<Void, String, Void>() {
#Override
protected Void doInBackground(Void... voids) {
while (i < 20) {
publishProgress(String.valueOf(i));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
mtoast.setText(values[0]);
mtoast.show();
mytv.setText(values[0]);
}
}.execute();
}
}
Want to know why only the last number ("20") is displayed omitting the intermediate ones(10 thru 19))
It doesn't work because you sleep the UI Thread.
To make this work, you would have to do it through a Thread, you can use an AsyncTask for this, or a Timer object as i specified below, anyways i recommend the use of AsyncTask.
Once i was doing something simmilar, you could use a Timer object for this.
Using the method: scheduleAtFixedRate(TimerTask task, long delay, long period)
The Docs for this method says
Schedules the specified task for repeated fixed-rate execution, beginning after the specified delay.
It means after the seconds from the second parameter, it will start, using the third parameter as delay for each execution. You will have to cancel it, calling the method:cancel();
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (counter == 20) {
timer.cancel();
counter = 0;
time.setText("Ta-da! I'm Done ");
}else{
counter += 1;
if (time != null)
time.setText(String.valueOf(counter));
}
}
});
}
}, delay, period);
Even further: A Thread.sleep is not the proper way to update a GUI and watch how it changes. The value it will take is the last one. The activity will be blocked until the last is shown.
If you want to see that effect, you should programm a Thread which communicates the main thread every X seconds, and the main thread should listen the Thread to change it.
For example, you could use an AsyncTask and use onProgressUpdate.
Edited with some code:
MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume(){
super.onResume();
/* Running AsyncTask */
myAsyncTask bkg = new myAsyncTask();
/* I'll pass an integer parameter: milliseconds to wait. */
bkg.execute(3000);
}
private class myAsyncTask extends AsyncTask<Integer, Integer, String> {
#Override
protected void onPreExecute() {
/* TODO: Do BEFORE background process */
Toast.makeText(getApplicationContext(),"I'm going to do a background task!", Toast.LENGTH_SHORT).show();
}
#Override
protected String doInBackground(Integer... parameters) {
/* TODO: What to do in Background */
/* Retrieving parameter passed */
int milliseconds = parameters[0];
try {
Thread.sleep(milliseconds);
publishProgress(milliseconds); /* Will prompt that value */
} catch (InterruptedException e) {
e.printStackTrace();
return "ERROR";
}
int i = 0;
while (i++ < 20) {
try {
Thread.sleep(milliseconds);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
return "ERROR";
}
}
return "OK";
}
#Override
protected void onPostExecute(String result) {
/* TODO: After execution of thread */
if(result.equals("OK"))
Toast.makeText(getApplicationContext(),"Correctly Processed", Toast.LENGTH_SHORT).show();
if(result.equals("ERROR"))
Toast.makeText(getApplicationContext(),"Failed", Toast.LENGTH_SHORT).show();
}
#Override
protected void onProgressUpdate(Integer... values) {
/* TODO: Here you can access UI elements as your TextView */
TextView tv = (TextView) findViewById(R.id.tvExample);
tv.setText(values[0]+"");
}
}
}
layout/main_activity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.myapplication2.app.MainActivity"
android:id="#+id/whatever">
<TextView
android:text="#string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:id="#+id/tvExample" />
Use the code (tested on device) provided below:
public class TestActivity extends Activity {
private Handler mHandler;
public TextView mytv;
private int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toast_showing_acounter);
mytv = (TextView) findViewById(R.id.myhw);
mHandler = new Handler();
i = 10;
scheduleHandler();
}
private void scheduleHandler() {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
showCounter();
if (i < 20) {
scheduleHandler();
}
}
}, 5000);
}
private void showCounter() {
Toast.makeText(this, String.valueOf(i), Toast.LENGTH_LONG).show();
mytv.setText(String.valueOf(i));
i++;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.test, menu);
return true;
}
}
Related
I want to show a "boot logo" or image before of setting the final layout of the main activity. Actually i do this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.authors);
mContext = this;
showAuthors();
where showAuthors run this:
private void showAuthors()
{
setContentView(R.layout.authors);
Thread logoTimer = new Thread() {
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
}
};
logoTimer.start();
try {
logoTimer.join();
setContentView(R.layout.activity_main);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
the file authors.xml ( R.layout.authors ) is the same of activity_main, but clean, containing just a pair of strings with my name and email:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:background="#raw/call2"
android:src="#raw/call2"
android:scaleType = "centerCrop"
tools:context=".MainActivity" >
<TextView
android:id="#+id/authorsTV"
android:textColor="#FF6600"
android:textSize="16.5sp"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="33dp"
android:text="#string/serviceStatus" />
</RelativeLayout>
the problem is: all works, but the screen is all white as an empty layout.
where i'm doing wrong? thank you all if consider to reply me!
You should not call thread.join from the main thread, because you can get an ANR crash.
Here's how to do it with minimal changes to your existing code. Remove everything after logoTimer.start(), and put this inside the try block, immediately after sleep(3000):
runOnUiThread(new Runnable(){
public void run(){
setContentView(R.layout.activity_main);
}
});
But it would be cleaner to rewrite that whole method like this:
private void showAuthors()
{
setContentView(R.layout.authors);
new Handler().postDelayed( new Runnable(){
public void run(){
setContentView(R.layout.activity_main);
}
}, 3000);
}
First you have two ways of showing a splash screen,
1.with activity
public class SplashActivity extends Activity implements Runnable
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
...
setContentView(R.layout.act_spalsh);
hideSplashActivity();
}
private void hideSplashActivity()
{
new Handler().postDelayed(this, 3000);
}
#Override //from runnable
public void run()
{
startActivity(new Intent(this, MainActivity .class));
finish();
}
2.with dialog
public class MainActivity extends Activity implements Runnable
{
Dialog splashDialog;
#Override
protected void onCreate(Bundle savedInstanceState)
{
...
splashDialog = new Dialog(this,android.R.style.Theme_Black_NoTitleBar_Fullscreen);
splashDialog.setContentView(R.layout.dlg_splash);
splashDialog.show();
hideSplashDialog();
setContentView(R.layout.act_main);
}
private void hideSplashDialog()
{
new Handler().postDelayed(this, 3000);
}
#Override //from runnable
public void run()
{
splashDialog.dismiss();
splashDialog = null;
}
I prefer using dialog unless you have some trouble with that
Okay this is driving me nuts. I have a worker thread, (Network call) that needs to run separate of the UI thread, (Its actually a ThreadPoolExecutor but I simplified it to prove my point). If you run this code in portrait, without rotation, the text updates. I put in the delay there to allow for rotations to show my issue. If you start in portrait and before text updates rotation to landscape the text does not update. If you comment the code you can see the listener fire but the text never updates.
I am trying to simulate a custom network call running in a separate thread that may take some time to come back if the user rotates in between then the data gets lost. We are trying to prevent multiple network calls to save data usage on a phone.
package com.example.test;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.res.Configuration;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int orientation = getResources().getConfiguration().orientation;
if (Configuration.ORIENTATION_LANDSCAPE == orientation) {
//Do SomeThing; // Landscape
} else {
startBackgroundWork();
//Do SomeThing; // Portrait
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private Handler mHandler = new Handler();
public void startBackgroundWork() {
new WorkingThread(new SomeListener() {
public void onSomethingDone(final Object result) {
mHandler.post(new Runnable() {
public void run() {
((TextView)findViewById(R.id.text)).setText((String)result);
//showMyDialog(result);
}
});
}
}).start();
}
public interface SomeListener {
public void onSomethingDone(Object result);
}
public class WorkingThread extends Thread {
private SomeListener mListener;
public WorkingThread(SomeListener listener) {
mListener = listener;
}
public void run() {
/* do some work */
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mListener.onSomethingDone("New Text");
}
}
}
It's because on rotation, the activity is re created, therefore all your code is binded to the old activity. You should make a reference to your working thread :
private static WorkingThread mWorkingThread;
public void startBackgroundWork() {
mWorkingThread = new WorkingThread(new SomeListener() {
public void onSomethingDone(final Object result) {
mHandler.post(new Runnable() {
public void run() {
((TextView)findViewById(R.id.text)).setText((String)result);
//showMyDialog(result);
}
});
}
}).start();
}
then onCreate update it :
public class WorkingThread extends Thread {
private SomeListener mListener;
public WorkingThread(SomeListener listener) {
mListener = listener;
}
public void run() {
/* do some work */
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mListener.onSomethingDone("New Text");
}
public void updateListener(SomeListener listener) {
mListener = listener;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startBackgroundWork();
}
public void startBackgroundWork() {
if (mWorkingThread == null || mWorkingThread.isFinished()) { // Use a boolean to know if it still running
mWorkingThread = new WorkingThread(new SomeListener() {
public void onSomethingDone(final Object result) {
mHandler.post(new Runnable() {
public void run() {
((TextView)findViewById(R.id.text)).setText((String)result);
//showMyDialog(result);
}
});
}
});
mWorkingThread.start();
} else {
mWorkingThread.updateListener(new SomeListener() {
public void onSomethingDone(final Object result) {
mHandler.post(new Runnable() {
public void run() {
((TextView)findViewById(R.id.text)).setText((String)result);
//showMyDialog(result);
}
});
}
});
}
}
But there is some improvments you could make :
The WorkingThread class should be static to avoid direct reference to the old activity : Java: Static vs non static inner class
Then make a reference to the current activity, and update it when it is recreated
Make a method for update of the text, instead of having the code directly in the listener
I need to show a second activity after the progress bar is filled. I tried the code below but it doesn't show the progress bar and just shows my second activity.
This is the code:
public class MiSuper2 extends Activity {
String strListas[] = null;
private ProgressBar mProgress;
private int mProgressStatus = 0;
private Handler mHandler = new Handler();
private StoreData stdArticulos = null;
public Cursor cursor = null;
private long fileSize = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
stdArticulos = new StoreData(this);
fileSize = 0;
setContentView(R.layout.main);
stdArticulos = new StoreData(this);
cursor = stdArticulos.leerArticulos();
mProgress = (ProgressBar) findViewById(R.id.progressbar_activity);
new Thread(new Runnable() {
public void run() {
while (mProgressStatus < 100) {
mProgressStatus = doWork();
mHandler.post(new Runnable() {
public void run() {
mProgress.setProgress(mProgressStatus);
}
});
}
}
}).start();
if(cursor.moveToFirst()) {
do{
strListas[cursor.getPosition()] = cursor.getString(cursor.getPosition());
}while(cursor.moveToNext());
}
Intent intent = new Intent(MiSuper2.this, PntArticulo.class);
startActivity(intent);
}
public int doWork() {
while (fileSize <= 1000000) {
fileSize++;
return (int) fileSize;
}
return 100;
}
}
This is the main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:orientation="vertical" >
<ImageView
android:id="#+id/imvLogo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/presentacion"
android:contentDescription="#string/logo"/>
<ProgressBar
android:id="#+id/progressbar_activity"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="200dp"
android:layout_height="wrap_content" android:layout_marginTop="100dp"/>
</LinearLayout>
Please help
It looks like you are using the doWork() function to take up time so that you're progress bar does something. Even though you wrote a big loop, it still executes very quickly so you don't see your progress bar move. Rather, you want to simulate your Thread doing something computationally intensive by using Thread.sleep() which takes an argument that is the time to sleep in milliseconds.
Try changing your code to this:
new Thread(new Runnable() {
public void run() {
while (mProgressStatus < 100) {
try {
mProgressStatus += doWork();
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.post(new Runnable() {
public void run() {
mProgress.setProgress(mProgressStatus);
}
});
}
runOnUiThread(new Runnable() {
#Override
public void run() {
startActivity(new Intent(MiSuper2.this, Second.class));
}
});
}
}).start();
And...
public int doWork() throws InterruptedException {
Thread.sleep(1000);
return 1;
}
This will increment your progress bar by 1% every second. And finally, the documentation on Thread.sleep(): https://developer.android.com/reference/java/lang/Thread.html#sleep(long)
EDIT: Ramz beat me to this answer, but doesn't provide an explanation of why it's the answer. Hopefully my explanation helps.
EDIT2: I think you edited your questions since I started looking at it a second time. You had some errors in your XML before, but now it is gone. Regardless, your problem is now that you need the call to startActivity() inside your worker thread. Otherwise, the UI thread does not wait for the doWork() function to return and immediately starts the other Activity when your app starts. Sorry, I should have mentioned this before. The code I posted above is updated with this change.
Please try this code SplashScreen.java
package com.cud.point;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import android.widget.TextView;
public class SplashScreen extends Activity {
ProgressBar bar;
TextView txt;
int total=0;
boolean isRunning=false;
// handler for the background updating
Handler handler=new Handler() {
#Override
public void handleMessage(Message msg) {
total=total+20;
String perc=String.valueOf(total).toString();
txt.setText(perc+"% completed");
bar.incrementProgressBy(20);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
bar=(ProgressBar)findViewById(R.id.progress);
txt=(TextView)findViewById(R.id.txt);
Handler x = new Handler();
x.postDelayed(new SplashHandler(), 5000);
}
class SplashHandler implements Runnable
{
public void run() {
// TODO Auto-generated method stub
startActivity(new Intent(getApplication(),YourSecound Activity.class));
SplashScreen.this.finish();
}
}
public void onStart() {
super.onStart();
// reset the bar to the default value of 0
bar.setProgress(0);
// create a thread for updating the progress bar
Thread background=new Thread(new Runnable() {
public void run() {
try {
for (int i=0;i<5 && isRunning;i++) {
// wait 100ms between each update
Thread.sleep(1000);
handler.sendMessage(handler.obtainMessage());
}
}
catch (Throwable t) {
} } });
isRunning=true;
// start the background thread
background.start();
}
public void onStop() {
super.onStop();
isRunning=false;
}
}
splash.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="15px" >
<TextView
android:id="#+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Loading......" />
<TextView
android:id="#+id/txt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/imageView1"/>
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/splash" />
<ProgressBar
android:id="#+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/imageView1"
android:layout_alignLeft="#+id/imageView1"
android:max="100" />
</RelativeLayout>
this is an example of my project so please make necessary change in xml file
in my app in android, i need change background image in image view on 10 seconds once. so that i call a Async Task within a run method. when I execute the app it crashes.
It gives the Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() Exception to me.
I know I have to use Thread, but I do not know how to do so properly. Please help me.
This is my code sample:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
.................
new Thread()
{
public void run()
{
while(true){
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
count = count + 1;
new ImageChange().execute();
}
}
}.start();
} // OnCreate End
class ImageChange extends AsyncTask<Void, Void, Void>
{
protected void onPreExecute() {
}
protected void onPostExecute(Void unused) {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
protected Void doInBackground(Void... arg0) {
switch(count){
case 1:
b1 = BitmapFactory.decodeFile(f1.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f2.getAbsolutePath());
break;
case 2:
b1 = BitmapFactory.decodeFile(f2.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f1.getAbsolutePath());
break;
default :
count = 0;
b1 = BitmapFactory.decodeFile(f1.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f2.getAbsolutePath());
break;
}
return null;
}
}
You're calling the AsyncTask from a worker Thread. This way it has no access to the UI thread. You probably should consider using a Handler.
Probably, the problem is that you must execute the ImageChange.doInBackground() method in the UI thread. Try to change your code like this:
class ImageChange extends AsyncTask<Void, Void, Void> {
Activity act;
public ImageChange(Activity act) {
this.act = act;
}
protected void onPostExecute(Void unused) {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
protected Void doInBackground(Void... arg0) {
switch(count) {
case 1:
helperMethod(f1.getAbsolutePath(), f2.getAbsolutePath());
break;
case 2:
helperMethod(f2.getAbsolutePath(), f1.getAbsolutePath());
break;
default :
count = 0;
helperMethod(f1.getAbsolutePath(), f2.getAbsolutePath());
break;
}
return null;
}
private void helperMethod(String a, String b) {
act.runOnUIThread(new Runable() {
public void run() {
b1 = BitmapFactory.decodeFile(a);
b2 = BitmapFactory.decodeFile(b);
}
});
}
}
Note that you must pass an Activity to the ImageChange class constructor. It means that you have to call the asyncTask in this way:
new ImageChange(this).execute();
Also consider the possibility of using the class TimerTask
EDIT: Change the Activity part of your code with this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
.................
new ImageChange().execute();
} // OnCreate End
And add the while(true) to the ImageChange class:
protected Void doInBackground(Void... arg0) {
while(true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = count + 1;
switch(count) {
...
}
}
return null;
}
EDIT2: You can solve the problem about onPostExecute inserting the code that must be execute after each iteration inside the while loop:
protected Void doInBackground(Void... arg0) {
while(true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = count + 1;
switch(count) {
...
}
act.runOnUIThread(new Runnable() {
public void run() {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
});
}
return null;
}
The code you insert inside the while loop must run in the UI thread; in fact, every onPostExecute method of the AsyncTask class runs on UI thread.
i solved the problem by using Handler Thread.
Ok this is a very weird problem I am having, and I'm pretty sure that I am messing up somewhere, but I can't quite figure out where.
What I am trying is -
Schedule a Timer to execute a TimerTask every five seconds
The TimerTask in turn executes an AsyncTask (which in this case simple sleeps for a second before returning the static count of the number of AsyncTasks).
Finally, the aforementioned count is updated in the UI.
And of course, the appropriate Handlers and Runnables have been used to post asynchronous messages from other threads to the UI.
This code executes only once. I expect it to fire every 5 seconds. Here's the code.
Note: I had no idea what to do with the Looper. I put it there after trial and error!
public class TimerAsyncMixActivity extends Activity {
public static final String TAG = "TimerAsyncMix";
static int executionCount = 0;
Handler mHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Timer().schedule(new MyTimerTask(this), 0, 5000);
}
class MyAsyncTask extends AsyncTask<String, Void, Integer>{
#Override
protected Integer doInBackground(String... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ++executionCount;
}
#Override
protected void onPostExecute(Integer result) {
mHandler.post(new UpdateUiThread(TimerAsyncMixActivity.this, result));
super.onPostExecute(result);
}
}
}
class MyTimerTask extends TimerTask{
private TimerAsyncMixActivity tma;
public MyTimerTask(TimerAsyncMixActivity tma) {
this.tma = tma;
}
#Override
public void run() {
Looper.prepare();
Log.d(TimerAsyncMixActivity.TAG, "Timer task fired");
tma.new MyAsyncTask().execute();
Looper.loop();
Looper.myLooper().quit();
}
}
class UpdateUiThread implements Runnable{
int displayCount;
TimerAsyncMixActivity tma;
public UpdateUiThread(TimerAsyncMixActivity tma, int i) {
this.displayCount = i;
this.tma = tma;
}
#Override
public void run() {
TextView tv = (TextView) tma.findViewById(R.id.tvDisplay);
tv.setText("Execution count is : "+displayCount);
}
Can anyone point me to what I'm doing wrong?
techie, this is how I implemented similar things. I'm won't claim that this is the best way, but it has worked for me and doesn't look too bad.
I have the following code in my activity. I create an async task when the activity starts and I stop it onPause. The AsyncTask does whatever it needs to do, and updates the UI on onProgressUpdate() (which is run on the UI thread, so there's no need to use a Handler).
private Task task;
#Override
protected void onPause() {
task.stop();
task = null;
}
#Override
protected void onResume() {
task = new Task();
task.execute();
}
private class Task extends AsyncTask<Void, String, Void> {
private boolean running = true;
#Override
protected Void doInBackground(Void... params) {
while( running ) {
//fetch data from server;
this.publishProgress("updated json");
Thread.sleep(5000); // removed try/catch for readability
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if( ! running ) {
return;
}
String json = values[0];
//update views directly, as this is run on the UI thread.
//textView.setText(json);
}
public void stop() {
running = false;
}
}
Do not use a timer. If your phone goes to sleep, the timer is suspended too. Use AlarmManager.