I'm trying to infinitely loop a thread but it keeps running only once. The only solutions I could find was for older version of Java which appear to not be working anymore.
Here is the Activity that starts the loop:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread growCoin = new Thread(new GrowingCoin());
growCoin.start();
}
}
Class that handles the loop:
public class GrowingCoin implements Runnable{
CoinTracker co = new CoinTracker();
boolean runGrowLoop = true;
public void run(){
try{
while(runGrowLoop == true){
co.copper = (int) (co.copper + (co.copper * 0.2));
MainActivity.coppertv.setText("Copper: " + co.copper);
Thread.sleep(1000);
Log.i("thread debug", "thread sleeping");
}
}
catch(Exception e){
}
}
}
I'm assuming it has something to do with the CoinTracker class not updating because I've had a similar problem before but if that is the case I do not know how to solve the problem.
Thanks in advance for any solutions/attempts at solving.
EDIT:
I have very little experience with LogCat but I assume the tag System.err means something important so here's everything I got from that tag. I cannot figure out what the error message means:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6247)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:902)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:4637)
at android.view.View.invalidateInternal(View.java:11690)
at android.view.View.invalidate(View.java:11654)
at android.view.View.invalidate(View.java:11638)
at android.widget.TextView.checkForRelayout(TextView.java:6842)
at android.widget.TextView.setText(TextView.java:4047)
at android.widget.TextView.setText(TextView.java:3905)
at android.widget.TextView.setText(TextView.java:3880)
at me.test.first.GrowingCoin.run(GrowingCoin.java:13)
at java.lang.Thread.run(Thread.java:818)
Becareful when doing something like while(runGrowLoop == true), it will take a lot of CPU resources. You should use synchronized block.
Take a look here, it already has an answer :
Android infinite loop in thread
Try it with an AsyncTask. And update your View through the OnProgressUpdate Methode.
You can do your stuff in the doInBackground method e.g.
protected Long doInBackground(URL... urls) {
while(runGrowLoop){
// Something to do.
publishProgress(1L)
}
}
You surely got exception at :
MainActivity.coppertv.setText("Copper: " + co.copper);
with some title of:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.
so you must do it something like:
MainActivity.coppertv.post(new Runnable() {
#Override
public void run() {
MainActivity.coppertv.setText("Copper: " + co.copper);}
});
or use
runOnUiThread(new Runnable() {
#Override
public void run() {
MainActivity.coppertv.setText("Copper: " + co.copper);}
});
to update the views.
Related
I wanted to mock location of a marker on map. I have list of LatLng values store in ArrayList. I use this value to update on map every second. I need this function to works in AsyncTask so that my UI thread will still responsive.
Initially, I tried using Thread.sleep() but made application not responsive.
protected String doInBackground(Void... voids) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
for (int i = 0; i < waypoint.size(); i++) {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(waypoint.get(i));
try {
Thread.sleep(1000); // Thread sleep made application not responsive.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, 500);
return null;
}
I also tried using .postDelayed but the integer i needs to get declared final which is a problem because I need the integer to change value.
protected String doInBackground(Void... voids) {
for (int i = 0; i < waypoint.size(); i++) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(waypoint.get(i)); // Integer i needs to declare final.
}
}, 1000);
}
return null;
}
Is there any way to do this? Thank you.
The Thread.sleep() approach is OK if you can spare a worker thread. The problem in your code is that the thread you are pausing is the UI Thread, that's why your application freezes. You have to understand that what your doing there is just publishing a runnable to the UI Thread using the Handler construct, nothing more.
In your second approach, you can dump the Handler part and use publishProgress (called from the background) after you override onProgressUpdate (delivered in UI thread) in your AsyncTask based class. It does effectively the same but with less boilerplate. Take a look at https://developer.android.com/reference/android/os/AsyncTask for details.
Finally, to circumvent the final requirement in anonymous classes, you can declare a final array of one element and use position 0 to read/write the value. Hopefully, you won't need to do this too often.
The fastest (but not the most correct when working with MultiThreading) way is:
protected String doInBackground(Void... voids) {
for (final TYPE_OF_WAYPOINT cWaypoint : waypoint) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(cWaypoint);
}
}, 1000);
}
return null;
}
I don't know what was the Type of "waypoint" List, so I wrote "TYPE_OF_WAYPOINTS" as placeholder.
#emandt answer does not work but the idea he gave could work. So I tried and it is working flawlessly with some modified from his answer:
protected String doInBackground(Void... voids) {
for (final TYPE_OF_WAYPOINT cWaypoint : waypoint) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(cWaypoint);
}
});
try {
Thread.sleep(1000);
} catch (Exception e) {
// catch exception here
}
}
return null;
}
Firstly, I have change the .postDelayed to .post. Then, to delay the operation by one second, I have added Thread.sleep(1000) inside for (...) but outside new Handler(Looper.getMainLooper()).post(...));.
Now, the application could do the process in the background with user still be able to interact with the UI. Thanks.
I have AsyncTask class with methods like this(class: ApiConnector):
#Override
protected String doInBackground(Void... voids)
{
return getToken(); //<-- do many the most important things and return String
}
and
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
and then in my Activity:
new ApiConnector()
{
#Override
public void onPostExecute(String result)
{
Log.d("here: ", result);
}
}.execute();
It work's fine when I execute this one time, but i have to do this in endless loop to take always fresh token like fresh apples in my market. I tried something like that:
while (true)
{
new ApiConnector()
{
#Override
public void onPostExecute(String result)
{
Log.d("here!", result);
}
}.execute();
Thread.sleep(1000);
}
and many many stupid things, but i can't find working way. All thread bussiness is tricky for me. Give me some kick and I manage this for sure.
You don't want to do this. All AsyncTasks run on one thread. If you infinitely loop inside an AsyncTask, you'll starve all other tasks. If you have each task start a new task, then you'll still risk major starvation issues.
If you want to do this (and I'm not sure you really do, but lets ignore that), the correct way is to use a Thread. A Thread can just have a giant while(true) loop and a sleep statement at the end.
Like hrskrs commented I would prefer using a Handler to execute something repeatedly. The main advantage is that postDelayed makes the run() method execute in the main application thread - so you can access and change UI components.
Here's an example:
public class MyTest implements Runnable {
private final static int INTERVAL = 5000;
private Handler mHandler;
private MyTest() {
mHandler = new Handler();
}
public void start() {
run();
}
public void stop() {
mHandler.removeCallbacks(this);
}
#Override
public void run() {
// put here the logic that you want to be executed
mHandler.postDelayed(this, INTERVAL);
}
}
I know timers work by making the thread sleep for x amount of time but I was wondering if there is some sort of timer out there that doesn't run on a thread that's not the UI thread. I thought about using a loop that constantly compares the system time in milliseconds, but I want to use that as a last resort as it does not seem very efficient.
EDIT:
Stacktrace:
07-25 14:38:38.037 22108-22124/com.example.myapp E/ViewRootImpl﹕ com.example.myapp.Main : Only the original thread that created a view hierarchy can touch its views.
java.lang.RuntimeException
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6355)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:929)
at android.view.ViewGroup.invalidateChildFast(ViewGroup.java:4466)
at android.view.View.invalidateViewProperty(View.java:11112)
at android.view.View.setTranslationY(View.java:10472)
at android.view.View.setY(View.java:10400)
at com.example.myapp.Player.update(Player.java:29)
at com.example.myapp.Main.update(Main.java:70)
at com.example.myapp.Main.access$000(Main.java:15)
at com.example.myapp.Main$1.run(Main.java:33)
at java.util.Timer$TimerImpl.run(Timer.java:284)
Relative Code:
if (!onGround){
playerVisual.setY(playerVisual.getY() + this.gravity);
}
if (playerVisual.getY() >= this.main.getDevice().getHeight() - 10){
this.onGround = true;
}
else {
this.onGround = false;
}
playerVisual is an ImageView if you were wondering.
This is a solution based on AsyncTask:
class AsyncTimer extends AsyncTask<Void, Void, Void>
{
boolean alive = true;
long startMS;
long intervalMS;
MainActivity activity;
public AsyncTimer(long startMS, long intervalMS, MainActivity activity)
{
this.startMS = startMS;
this.intervalMS = intervalMS;
this.activity = activity;
}
protected Void doInBackground(Void... params)
{
try
{
Thread.sleep(startMS);
}
catch (Exception e)
{
Log.e("Error", e.getMessage());
e.printStackTrace();
}
while (alive)
{
try
{
alive = activity.updateUI();
Thread.sleep(intervalMS);
}
catch (Exception e)
{
Log.e("Error", e.getMessage());
e.printStackTrace();
}
}
return null;
}
}
Using it in MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
...
new AsyncTimer(0, 1000, this).execute();
}
public boolean updateUI()
{
Log.d("Timer", "tick");
...
return true;
}
This is a solution for updating the GUI from a scheduled task. Use Handler instead of Timer
final Handler handler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
handler.postDelayed(myRunnable, 1000); //1 second
/*UPDATE GUI*/
update();
}
};
myRunnable.run();
You bascially want to block the current thread / wait on a condition - well
there are several options - the easiest one is to use Semaphore :
final Semaphore semaphore = new Semaphore(0); //not available at first
try
{
semaphore.tryAcquire(1, TimeUnit.SECONDS); //block for 1 second since it isnt available
}
catch(InterruptedException ex)
{
//do something sensible here
}
Another option is CountDownLatch :
final CountDownLatch latch = new CountDownLatch(1); //1 latch available
try
{
latch.await(1, TimeUnit.SECONDS) //since currently one latch is available this will timeout
}
catch(InterruptedException ex)
{
//do something sensible here
}
Granted : thats somewhat of an abuse of these classes, but it works flawlessy.
You could even use Object.wait but since an object can receive "spurious wakeups" you would have to deal with those - which isnt always as easy as it may appear to be at first.
Basically, you can use pretty much any mechanism which allows you to reliably "wait" on something - until your next time-slice is ready to be taken (hence : timeout on something) and continue in your loop.
In languages other than Java its possible to (reliably) suspend / pause the current thread for a fixed amount of time - thats even better but it breaks quite a few programming paradigms and it can be hard to understand; its best to not touch the thread itself unless you're really experienced and have a lot of knowledge about these things, blocking method invocations are almost always the best choice, even if that means writing a few extra lines of code.
I have a for loop which calls a function to download a file.
Each time the function is called the title of the file is displayed in a TextView.
The problem is the files are downloaded but the UI freezes up, and it is only after the files have finished downloading that the UI is updated, and only the last title for the last file is shown.
for(int i=0; i < Titles.size(); i++){
downloading.setText("Downloading: "+Titles.get(i));
if(!Utils.downloadFile(Mp3s.get(i))){
downloading.setText("ERROR Downloading: "+Titles.get(i));
}
}
I know I have to use a Handler or Thread to sort this issue out.
But I am not sure how to implement it.
You could try using Activity.runOnUiThread() - something like:
// Move download logic to separate thread, to avoid freezing UI.
new Thread(new Runnable() {
#Override
public void run() {
for(int i=0; i < Titles.size(); i++) {
// Those need to be final in order to be used inside
// Runnables below.
final String title = Titles.get(i);
// When in need to update UI, wrap it in Runnable and
// pass to runOnUiThread().
runOnUiThread(new Runnable() {
#Override
public void run() {
downloading.setText("Downloading: "+title);
}
});
if(!Utils.downloadFile(Mp3s.get(i))) {
runOnUiThread(new Runnable() {
#Override
public void run() {
downloading.setText("ERROR Downloading: "+title);
}
});
}
}
}).start();
That's pretty verbose (yeah, Java!) and, in my opinion, not very readable.
Another solution would be to use AsyncTask, which has convienient onProgressUpdate() method designed to update UI for a long-running task. It could look like:
public class DownloadTask extends AsyncTask<URL, String, Void> {
// This method will be run off the UI thread, no need to
// create separate thread explicitely.
protected Long doInBackground(URL... titles) {
for(int i=0; i < titles.length; i++) {
publishProgress("Downloading " + titles[i]);
if(!Utils.downloadFile(Mp3s.get(i))) {
publishProgress("ERROR Downloading: " + titles[i]);
}
}
}
// This method will be called on the UI thread, so
// there's no need to call `runOnUiThread()` or use handlers.
protected void onProgressUpdate(String... progress) {
downloading.setText(progress[0]);
}
}
(please note that code above is hand-written not-compiled, so it's probably buggy, but it should give you an idea how to go from here.
Tons of JProgressBar questions on here I know, but through all the answers and I can't seem to diagnose my issue. I am processing a file with some address verification software. I click the Process button and I need my JProgressBar to update with each file processed.
Here is the button:
private JButton getJButton0() {
...
jButton0.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
jButton0ActionActionPerformed(event);
t.start();
}
...
Per everybody's recommendation, I used the setValue() method within a thread
Thread t = new Thread(){
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jProgressBar0.setValue(BulkProcessor.getPercentComplete());
}
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
...
BulkProcessor.getPercentComplete() is a method I'm calling from another class which represents the percentage complete. I have tested this method and it updates correctly. The issue is that the progress bar will not update until the files are finished processing, and then it will jump to 100%. I apologize if this is a repeat question, but I have done some serious digging on this site with no luck. Any help much appreciated.
Edit:
Per recommended duplicate, I tried this:
public void update(){
new SwingWorker<Void,Void>() {
protected Void doInBackground() throws Exception {
jProgressBar0.setValue(BulkProcessor.getPercentComplete());
return null;
};
}.execute();
}
And then tried calling this update() method under the actionPerformed() (switched t.start() with update()). I am still having the same issue.
Edit
Based on user1676075's recommendation, however same issue:
public static void update(){
new SwingWorker<Void,Integer>() {
protected Void doInBackground() throws Exception {
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentComplete);
Thread.sleep(100);
} while(percentComplete < 100);
return null;
}
#Override
protected
void process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
}
Edit
Here is the code from my BulkProcessor class
private String getOutputLine( String searchString, String inputLine )
throws QasException
{
..(code for processing lines)..
countRecord++;
percentComplete = (int) Math.round((countRecord/totalRecord)*100);
totalRecord is updated in the main class of my BulkProcessor class
public static void main( String input, String output ){
count.clear();
try{
String inputFile = input;
String outputFile = output;
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(input)));
lnr.skip(Long.MAX_VALUE);
totalRecord = lnr.getLineNumber() + 1; //line count in file
BulkProcessor bulk = new BulkProcessor(inputFile, outputFile, ConfigManager.DFLT_NAME);
bulk.process();
}catch(Exception e ){
e.printStackTrace();
}
}
Looks like you're mixing usages. See the SwingWorker documentation, example at the top: http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html.
Ideally you'd update your BulkProcessor in the doInBackground method of the SwingWorker, and that would call setProgress, and the jProgressBar would be listening for those progress updates as in the example.
If that won't work for you, which it seems like it won't just based on the above, start a SwingWorker from the button press event. Implement the SwingWorker methods kinda like this (pseudocode):
new SwingWorker<Void,Integer>()
{
doInBackground()
{
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentCompete);
Thread.sleep(100);
} while (percentComplete < 100);
}
#Override
process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
You'll need to add error-handling and checks for complete and failure cases, but that should get you started and to where you want to be. doInBackground runs in a background thread so won't block anything, and process() runs on the swing worker thread so will post the updates.
The mistake you probably went on is calling the t.start(); after thejButton0ActionPerformed(event); which makes that after the action is performed the thread will start. Therefore the value of the progress bar is not updated as intended.
You need to start the thread in jButton0ActionPerformed(event); and then update the value in it.
Just a hunch, but...
percentComplete = (int) Math.round((countRecord/totalRecord)*100);
Are you sure this is not integer arithmetic? I don't know the type of totalRecord, so I can't say for sure.
I'd guess everything works fine, and just the progress is 0 all the time, until complete where it magically is 100. This is because an int divided by an int will not have fraction values (ie. 99/100 == 0, 100/100 == 1). This fits perfectly with the symptoms you are experiencing.
Try replacing the line above with:
percentComplete = (int) Math.round((countRecord/(double) totalRecord)*100);
to see it I'm right. :-)
Have you tried to use the PropertyChangeListener-interface?
The calculations will be done by the Swingworker-thread and the main-gui will implement this interface. Some example-code
#Override
public void actionPerformed(ActionEvent e) {
this.myButton.setEnabled(false);
MyWorkerThread thread = new MyWorkerThread(); //Data-processing
thread.addPropertyChangeListener(this.mainguiframe); //Separation of concern
thread.execute();
}
Using the "setProgress"-method of the swing-worker-thread the main-gui-thread will be notified if something has happend.
#Override
public void propertyChange(PropertyChangeEvent property) {
Integer currentValue = new Integer(0);
currentValue = (Integer) property.getNewValue();
this.progressBar.setValue(currentValue.intValue());
}
Swing is not thread-safe. This is not the best solution but perhaps it can help you. Please comment if there is somethin horrible wrong.