I am trying to create a loop that will update a TextView.
The idea is to create some sort of progress indicator, that will increment the
loading precentge.
This is what I have tried, but the result is that I see only the last update of the loop, so I get "100%" with no incremntation.
runOnUiThread(new Runnable() {
public void run() {
final TextView progesss = (TextView)findViewById(R.id.progress);
for(int k=1 ; k<=100; k++)
{
progesss.setText(String.valueOf(k) + "%");
try {
Thread.sleep(15);
} catch(InterruptedException e) {
}
}
}
});
Any ideas of how to achieve my goal?
Thanks!
Your Runnable blocks the UI thread when doing Thread.sleep. Instead of sleeping, you should post a new Runnable again. Try with something like this:
final Handler handler = new Handler();
handler.post( new Runnable(){
private int k = 0;
public void run() {
final TextView progess = (TextView)findViewById(R.id.progress);
progess.setText(String.valueOf(k) + "%");
k++;
if( k <= 100 )
{
// Here `this` refers to the anonymous `Runnable`
handler.postDelayed(this, 15);
}
}
});
That will give the UI thread a chance to run between each call, letting it do its stuff like handling input and drawing stuff on the screen.
You use background thread and UI Thread.
public class testAsync extends AsyncTask<Void, Integer, Voi>{
TextView progress; // You will set TextView referans
protected void doInBackground(){
for(int k=1 ; k<=100; k++)
{
try {
Thread.sleep(1000);
publishProgress(k);
} catch(InterruptedException e) {}
}
}
protected void onProgressUpdate(Integer.. values)
{
progress.setText(values[0]+");
}
}
}
Related
I would like to add some ImageViews to a RelativeLayout view.
The code that I'm using is as follows:
Thread thread = new Thread(new Runnable() {
ArrayList<ImageView> icons = new ArrayList<ImageView>();
#Override
public void run() {
for (int i = 0; i < 20; i++) {
ImageView imageView1 = new ImageView(G.context);
imageView1.setImageResource(R.drawable.music_icon);
imageView1.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
imageView1.getLayoutParams().width = (int) convertDpToPixel(20);
imageView1.getLayoutParams().height = (int) convertDpToPixel(20);
icons.add(imageView1);
Log.i("LOG", "Icons Size: " + icons.size());
Log.i("LOG", "I: " + i);
relativeLayout.addView(icons.get(i));
icons.get(i).startAnimation(animationMusic);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
The first time the loop runs fine, but the second time there's an error in the line:
relativeLayout.addView(icons.get(i));
Where is the problem?
One major problem is manipulating the view (e.g. adding a View) from a background thread. You can get similar async behavior by making use of Android's AsyncTask objects and do any UI manipulation from the onPostExecute method.
Without know more about what you're doing, it's hard to find a solution that will work for you. I was mainly pointing out a primary issue with your code.
Here is an attempt to rewrite your code in a way that might work better in an Android environment:
public void addImageViews() {
for(int i = 0; i < 20; i++) {
asyncAdd(i, G.context);
}
}
protected void asyncAdd(final int index, final Context c) {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(3000 * index);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
relativeLayout.addView(generateImageView(c));
}
}.execute();
}
protected ImageView generateImageView(Context c) {
ImageView imageView1 = new ImageView(c);
imageView1.setImageResource(R.drawable.music_icon);
imageView1.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT));
imageView1.getLayoutParams().width = (int) convertDpToPixel(20);
imageView1.getLayoutParams().height = (int) convertDpToPixel(20);
return imageView1;
}
I have three strings
String one="Connecting.";
String two="Connecting..";
String three="Connecting...";
I have a textView, what I want is to set text to textview in this order..
one-->two-->three-->one-->two-->three and so on until the process is completed.
I have done it in a for loop based on value i.e
if(value%3==0){
tx.setText(one);
}
else if(value%3==1){
tx.setText(two);
}
else
{
tx.setText(three);
}
This is done inside a thread and it is working well.
But I dont want to rely on "value".. I jst want that until process is completed the text changes in order as mentioned above.
I know it is vague but I am not getting how to do this.
Please if someone can give any hint.
code:
public void startProgress(View view) {
bar.setProgress(0);
tx.setText("Connect");
new Thread(new Task()).start();
}
class Task implements Runnable {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
try {
Thread.sleep(500);
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
bar.setProgress(value);
String one="Connecting.";
String two="Connecting..";
String three="Connecting...";
if(value%3==0){
tx.setText(one);
}
else if(value%3==1){
tx.setText(two);
}
else
{
tx.setText(three);
}
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
It makes sense to have a counter like value that keeps incrementing. But you could do it a little more simply:
String[] texts = new String[3] {"Connecting.", "Connecting..", "Connecting..."};
int value = 0;
// ...
tx.setText(texts[value]);
value = (value+1)%3;
This way, you don't need your big messy if statement. You will need to find another way of notifying your thread when the job is done, rather than just having a fixed number of iterations.
Use TextSwitcher instead of TextView...It will work
My MainActivity has 2 views: TextView and a Button. On button click, I am running an AsyncTask which further creates 10 new AsyncTasks for network operations. Every new task creation is delayed by 1 sec. The code is:
public class MainActivity extends ActionBarActivity
{
TextView tv;
Button t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView1);
t = (Button) findViewById(R.id.toggleButton1);
t.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
getData();
}
});
}
void getData()
{
SuperNetworkAsyncTask s = new SuperNetworkAsyncTask();
s.execute("");
}
private class SuperNetworkAsyncTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
for(int i=0;i<10;i++)
{
{
nTask = new NetworkAsyncTask();
nTask.execute("");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return "";
}
#Override
protected void onPostExecute(String result)
{
}
}
private class NetworkAsyncTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
return String.valueOf(System.currentTimeMillis());
}
#Override
protected void onPostExecute(String result)
{
tv.setText(result);
}
}
}
I was expecting that the moment first NetworkAsyncTask execute method is called, it will start execution. But when I run it, I do not find any NetworkAsyncTask begin its execution until the control comes out of SuperNetworkAsyncTask. Is there any way to push the execution of NetworkAsyncTask thread as soon as execute method is called?
Some clarifications:
Why NetworkAsyncTask are created by SuperNetworkAsyncTask? Because If I create the NetworkAsyncTask in main thread, I get my UI freeze for some time.
Why making 10 object? The purpose of NetworkAsyncTask is to read data from a server at interval of 1 sec for n seconds, here n=10.
Part 2: Updates after doing some tests.
Observation 1:
As a fellow Brian shared a way to avoid creating AsyncTasks in nested way, I tried his code:
void getData() {
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
nTask = new NetworkAsyncTask();
nTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
new Thread(runnable).start();
}
This freezes my UI for few seconds and then the screen is updated in a fraction of second. It is quite surprising to me too.
Observation 2:
With java.lang.Thread, I experimented to make sure that 1) The threads should be executed right away when run() called. 2) The next task will be created only after previous task is finished.
Code:
public static void main(String[] args) {
myThread m;
for (int i=0;i<10;i++)
{
m=new myThread(String.valueOf(i));
m.start();
synchronized (m)
{
try {
m.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class myThread extends Thread
{
public String name = "";
public myThread(String n)
{
name = n;
}
public void run()
{
synchronized (this)
{
System.out.println(" Thread Name = " + name);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyAll();
}
}
}
Output:
Thread Name = 0
Thread Name = 1
Thread Name = 2
Thread Name = 3
Thread Name = 4
Thread Name = 5
Thread Name = 6
Thread Name = 7
Thread Name = 8
Thread Name = 9
Based in this, I updated my NetworkAsyncTask & SuperNetworkAsyncTask as:
private class NetworkAsyncTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
synchronized (this)
{
return String.valueOf(System.currentTimeMillis());
}
}
#Override
protected void onPostExecute(String result)
{
synchronized (this)
{
tv.setText(result);
notifyAll();
}
}
}
private class SuperNetworkAsyncTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
for(int i=0;i<10;i++)
{
nTask = new NetworkAsyncTask();
nTask.execute(url);
synchronized (nTask)
{
try {
nTask.wait();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return "";
}
#Override
protected void onPostExecute(String result)
{
}
}
With this code the wait() keeps on waiting indefinitely.
Finally I replaced:
nTask.execute(url);
with
nTask.executeOnExecutor(THREAD_POOL_EXECUTOR, "");
This worked well as expected.
The UI will be updated only at onPostExecute(). See notes on AsyncTask
Click here! And Try to avoid 10 AysncTasks, it does not make any sense.
You don't need to use a "super async task" use a runnable and then create new async tasks in parallel
void getData() {
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
nTask = new NetworkAsyncTask();
nTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
new Thread(runnable).start();
}
Post honeycomb you can specify to run async tasks in parallel
An AsyncTask should be started in the UI thread, not on the one doInBackground runs on. You could call publishProgress after every sleep, and spawn each AsyncTask in the resulting calls to onProgressUpdate, which run on the UI thread.
I am trying to publish two different kinds of progress in my background process. I am trying to publish a string sometime and an integer another time. I am handling both kinds of arguments in the onProgressUpdate by overloading them too. But when I declare my AsyncTask class, I have the arguments that is why it is expecting me to send only string type arguments. Is there a way to handle both type of publishProgress events?
Basically there are two ways to address your issue:
The first one is very simple, where you just always publishUpdate(String), and then in your onProgressUpdate(String) checks whether the string is an int or a string, and handle each case differently like this:
private class MyAsyncTask extends AsyncTask<Void, String, Void> {
//Executed on main UI thread.
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
try{
Integer i = Integer.parseInt(values[0]);
TextView v1 = (TextView) findViewById(R.id.textView1);
v1.setText(String.valueOf(i));
}
catch(NumberFormatException e){
TextView v2 = (TextView) findViewById(R.id.textView3);
v2.setText(values[0]);
}
}
#Override
protected Void doInBackground(Void... params) {
int i = 0;
while(i < 100){
try {
if(i%2 == 0){
publishProgress("Divisible by 2: " + String.valueOf(i));
}
publishProgress(String.valueOf(i));
i++;
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
In the above example I just try and parse the string to an Integer - if it works then I am 100% sure it is an int - if it throws an exception then it is a String.
If you want more control however, you need to implement your own version of AsyncTask, that support one or more progress updates. The only way you can achieve this is by using Handlers (http://developer.android.com/reference/android/os/Handler.html) and Thread (http://developer.android.com/reference/java/lang/Thread.html) directly (preferably wrapped in a more logical class similar to AsyncTask):
import android.os.Handler;
import android.os.Looper;
public abstract class DIYAsyncTask<Params, IntProgress, StringProgress, Result> {
private Result backGroundResult;
//Run on UI thread
#SuppressWarnings("unchecked")
protected void execute(Params... params){
final Params[] thisParams = params;
Thread worker = new Thread(){
public void run(){
prepareForPreExecute();
backGroundResult = doInBackground(thisParams);
prepareForPostExecute();
}
};
worker.setPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
worker.start();
}
//Code to start onPreExecute on UI thread
private void prepareForPreExecute(){
Handler ui_handler = new Handler(Looper.getMainLooper());
ui_handler.post(
new Runnable(){
public void run(){
onPreExecute();
}
}
);
}
//Code to start onPostExecute on UI thread
private void prepareForPostExecute(){
Handler ui_handler = new Handler(Looper.getMainLooper());
ui_handler.post(
new Runnable(){
public void run(){
onPostExecute(backGroundResult);
}
}
);
}
//Always run on worker thread
#SuppressWarnings("unchecked")
protected abstract Result doInBackground(Params... params);
//Always run on UI
protected void onPreExecute(){
}
//Always run on UI
protected void onPostExecute(Result result){
}
//Run on worker
#SuppressWarnings("unchecked")
protected void publishIntProgress(IntProgress... values){
Handler ui_handler = new Handler(Looper.getMainLooper());
final IntProgress[] thisProgress = values;
ui_handler.post(
new Runnable(){
#Override
public void run(){
onIntProgressUpdate(thisProgress);
}
}
);
}
//Always run on UI
#SuppressWarnings("unchecked")
protected void onIntProgressUpdate(IntProgress... values){
}
//Run on worker
#SuppressWarnings("unchecked")
protected void publishStringProgress(StringProgress... values){
Handler ui_handler = new Handler(Looper.getMainLooper());
final StringProgress[] thisProgress = values;
ui_handler.post(
new Runnable(){
#Override
public void run(){
onStringProgressUpdate(thisProgress);
}
}
);
}
//Always run on UI
#SuppressWarnings("unchecked")
protected void onStringProgressUpdate(StringProgress... values){
}
}
Which you can then override like this (notice the similarity to just using AsyncTask)
private class MyDIYAsyncTask extends DIYAsyncTask<Void, Integer, String, Void> {
//Executed on main UI thread.
#Override
protected void onIntProgressUpdate(Integer... values) {
super.onIntProgressUpdate(values);
TextView v = (TextView) findViewById(R.id.textView1);
v.setText(String.valueOf(values[0]));
}
#Override
protected void onStringProgressUpdate(String... values) {
super.onStringProgressUpdate(values);
TextView v = (TextView) findViewById(R.id.textView3);
v.setText(values[0]);
}
#Override
protected Void doInBackground(Void... params) {
int i = 0;
while(i < 100){
try {
publishIntProgress(i);
publishStringProgress("MyString" + String.valueOf(i));
i++;
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
I make a game about 8Puzzle on android with AI using A* algorithm.
Everything works fine but there is a problem, there are some function that is executed in parallel.
What I want is the function is executed after another function is finished.
Here is code:
if(AItype.equals("A*"))
{
DisableButton();
DisableClickImageView();
AStarSolver as = new AStarSolver();
as.solvePuzzle(arr, GOAL); //Solve the puzzle
displayResult(as.solutionPath); //display animation
as = null;
Toast.makeText(getApplicationContext(), "Finished", Toast.LENGTH_LONG).show();
copySTARTtoArray();
setImageResource();
EnableButton();
}
I want text "Finished" is displayed after function displayResult() is finished but the text "Finished"
show at the same time with function displayResult().
How to solve this??
Edit:
Here is the code for displayResult();
public void displayResult(final Stack<Node> solutionPath)
{
Handler handler = new Handler();
for (int i = 0; i < solutionPath.size(); i++)
{
handler.postDelayed(new Runnable() {
public void run() {
Node solNode = solutionPath.pop();
//solNode.NodeState.
tile00.setImageResource(solNode.getImageResourceBasedNodeState(0));
tile01.setImageResource(solNode.getImageResourceBasedNodeState(1));
tile02.setImageResource(solNode.getImageResourceBasedNodeState(2));
tile10.setImageResource(solNode.getImageResourceBasedNodeState(3));
tile11.setImageResource(solNode.getImageResourceBasedNodeState(4));
tile12.setImageResource(solNode.getImageResourceBasedNodeState(5));
tile20.setImageResource(solNode.getImageResourceBasedNodeState(6));
tile21.setImageResource(solNode.getImageResourceBasedNodeState(7));
tile22.setImageResource(solNode.getImageResourceBasedNodeState(8));
}
}, 800 * (i + 1));
}
}
It display the result of animation (Ex: tile0 to tile1)
Try this.
public void displayResult(final Stack<Node> solutionPath)
{
Handler handler = new Handler();
for (int i = 0; i < solutionPath.size(); i++)
{
handler.postDelayed(new Runnable() {
public void run() {
Node solNode = solutionPath.pop();
//solNode.NodeState.
tile00.setImageResource(solNode.getImageResourceBasedNodeState(0));
.
.
.
tile22.setImageResource(solNode.getImageResourceBasedNodeState(8));
}
}, 800 * (i + 1));
}
// Put following code
handler.postDelayed(
new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "Finished", Toast.LENGTH_LONG).show();
}
},800*(solutionPath.size()+1)
);
}
Your code should be look like this.
solvePuzzle(...){
// solved #1
displayResult(...){
}
// solved #2
displayResult(...){
}
}
or use thread.
as.solvePuzzle(arr, GOAL); //Solve the puzzle
displayResult(as.solutionPath); //display animation
means solvePuzzle is all done, then call displayResult.
function(){
//code of this function
function1();
}
function1(){
//code of this function
function2();
}
function2(){
}