I have a CustomAsyncTask class that enables infinite barcode scanner and I execute it in CustomApplication.
Unfortunately CustomAsyncTask::doInBackground stops after some time (minute or two).
private class ScanAsync extends AsyncTask<Void, String, Void>
{
boolean blocked = false;
#Override
protected Void doInBackground(Void... params)
{
while(true)
{
if (!blocked)
{
String received = GlobalAccess.scan.scan(500);
if (received != null && !received.isEmpty())
{
blocked = true;
publishProgress(received);
}
}
else
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
#Override
protected void onProgressUpdate(String... values)
{
super.onProgressUpdate(values);
//TODO: something with received value
blocked = false;
}
}
I need this background task to be always on. Is there any good solution for this? I have tried IntentService, but the result was the same - after some time it stopped working.
EDIT
I have created this Service, although it block my main thread, but it should work in background right? Also If I put a breakpoint on if(!blocked) and press F9 it works fine (scanning part), but if I remove breakpoint and let it run - after few seconds it just turns off (scanner), but if I put a breakpoint again - it works again (sic!).
public class ScanService extends Service
{
boolean blocked = false;
public ScanService()
{
}
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
while(true)
{
if (!blocked)
{
String received = GlobalAccess.scan.scan(500);
if (received != null && !received.isEmpty())
{
//blocked = true;
}
}
else
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
}
Use a Service instead of AsyncTask. AsyncTasks are only designed to run with shorter background tasks. Keep in mind that whatever you run in a Service will execute on the main thread, so you should use a background thread within your Service.
Can you tell why the AsyncTask or IntentService is stopping? With an IntentService, with your while(true) loop, it should run indefinitely unless the app gets shut down for some reason.
Edit -
You need to do this to prevent your loop from blocking the main thread -
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(true) {
// your code here
}
}
});
t.start();
}
I don't know why your Service is stopping. You need to be looking at your Logcat output. Set the filter to Error and you're crash should show up there.
Yes, there is an elegant solution for this type of thing. Use a service. In particular, the JobScheduler api is meant to handle this kind of stuff. Reason for using this is, as you stated, you have a long running task and you don't want to have to manage it dying. In addition, the JobScheduler is built to handle side effects of the OS. I assume that you want your job to run, but allow the app to perform its normal set of operations. Though, as a note, the API is smart in considering factors, such as battery levels, OS resources being used, wifi connectivity, so the jobs can be deferred.
The official documentation is here https://developer.android.com/reference/android/app/job/JobScheduler.html
An example of how to use it can be found here
https://code.tutsplus.com/tutorials/using-the-jobscheduler-api-on-android-lollipop--cms-23562
Related
here is my piece of code:
Thread one = new Thread() {
public void run() {
try {
new LongOperation(finalJson)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
.get(30000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
};
one.start();
i want to say if AsyncTask past 30000 MILLISECONDS and didn't finish the job return a message, how i can code this? thanks
I would prefer doing it using an AsyncTask.
Copy-pasting from the link:
AsyncTask enables proper and easy use of the UI thread. This class
allows you to perform background operations and publish results on the
UI thread without having to manipulate threads and/or handlers.
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. AsyncTasks
should ideally be used for short operations (a few seconds at the
most.) If you need to keep threads running for long periods of time,
it is highly recommended you use the various APIs provided by the
java.util.concurrent package such as Executor, ThreadPoolExecutor and
FutureTask.
Said this, configuring an AsyncTask is pretty simple, just create a class like the following:
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method works on the UI thread.
//this is the first to run before "doInBackground"
mTextView.setText("we start!");
}
#Override
protected String doInBackground(String... params) {
try {
//do whatever your async task needs to do. This method works async
//you can also call an UI callback from here with the publishProgress method. This will call the "onProgressUpdate" method, and it has to respect his type.
publishProgress("we go on!");
} catch (InterruptedException e) {
Thread.interrupted();
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//this method works on the UI thread
//it get the "doInBackground" return value.
mTextView.setText(result);
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(String... values) {
//this method works on UI thread, so it can access UI components and ctx
mTextView.setText(values[0]);
}
}
This is a basic example on how to create an AsyncTask, you can use it like this (form activity/fragment):
AsyncTaskExample asyncTask = new AsyncTaskExample();
asyncTask.get(30000, TimeUnit.MILLISECONDS);
This will set a timeout on your async operation. Look here for the exact Exception/return
For any further question, ask freely. Hope this helps
Edit:
I just noticed you have an AsyncTask inside your thread. Since AsyncTask is already async, I would avoid doing this and simply call the AsyncTask with the method I gave you before. In that way the AsyncTask will run up to the given TimeSpan :)
See the code below: It may help you.
CountDownTimer timer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//return a message here;
}
};
timer.start();
And if you have an async task. Then do like below in doInBackground method:
#Override
protected Void doInBackground(Void... voids) {
//simply do your job
CountDownTimer timer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//return a message here;
return message;
}
};
timer.start();
return your_reult;
}
I am starting a new thread in my app's onCreate() method like so:
stepsLogger = new Runnable() {
while(!Thread.currentThread().isInterrupted()){
//my code
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
loggerThread = new Thread(stepsLogger);
loggerThread.start();
While it is not interrupted, it is supposed to do its thing every 10 seconds.
I am logging some text at the start of the Runnable to see how often the code gets run. The first time I run the app it's fine, but every time i restart, the text gets logged more frequently which means that more threads are running.
I have tried to stop them in the onDestroy() method:
#Override
protected void onDestroy() {
super.onDestroy();
loggerThread.interrupt();
loggerThread = null;
}
How do I make sure that the old thread gets stopped whenever the app is restarted?
Thread.interrupt() will wake up a sleeping thread with an InterruptedException, so you're most of the way there already. I'd change your loop in the following way:
while (true) {
// some code
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore the thread's interrupted flag
break;
}
}
The bit about re-interrupting the thread is subtle. You can read more about it in this post from one of the primary JVM architects: https://www.ibm.com/developerworks/library/j-jtp05236/
In case this link ever dies, the gist of it is that there can be multiple "recipients" of thread interruption. Catching the exception implicitly clears the thread's interrupted flag, so it's useful to set it again.
You could use a volatile boolean variable to determine when to stop. Something like this:
class WorkerRunnable implements Runnable {
private volatile boolean shouldKeepRunning = true;
public void terminate() {
shouldKeepRunning = false;
}
#Override
public void run() {
while (shouldKeepRunning) {
// Do your stuff
}
}
}
To start it:
WorkerRunnable runnable = new WorkerRunnable();
new Thread(runnable).start();
To stop it:
runnable.terminate();
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'm new to Java so sorry if the problem is trivial. My code is probably a mess. I created a online radio player for Raspberry Pi in Java and I have to do a POST request every 10 seconds to check what is the current song playing and if the song has changed, I have to do some things (like scrobble old song, update display with new song data, store play session to my server etc.). I created a class for this:
public class Scrobbler implements Runnable, Commands, Observer {
private TimeCounter counter;
private Timer timer;
private Radio radio;
private List<Observer> observers;
private final Object MUTEX= new Object();
private int currentPlaySession;
// And all other variables which I deleted before posting
// Constructor
public Scrobbler(TimeCounter _counter, Radio _radio)
{
currentTrack = null;
counter = _counter;
radio = _radio;
timer = null;
observers = new ArrayList<>();
currentPlaySession = 0;
}
private void GetInfo()
{
// POST request to get current song playing
// If song has changed, notify observers
}
public void Scrobble()
{
// POST request - Scrobble song to my website and last.fm
}
public void StartPlaySession()
{
// Again POST request to my website
}
public void EndPlaySession()
{
// Again POST request to my website
}
#Override
public void start() {
new Thread(this).start();
}
public void stop()
{
timer.cancel();
timer.purge();
timer = null;
}
#Override
public void register(Observer obj) {
if(obj == null) throw new NullPointerException("Null Observer");
synchronized (MUTEX) {
if(!observers.contains(obj)) observers.add(obj);
}
}
#Override
public void unregister(Observer obj) {
synchronized (MUTEX) {
observers.remove(obj);
}
}
#Override
public void notifyObservers(String command) {
for (Observer obj : observers) {
obj.update(command);
}
}
#Override
public void run() {
timer = new Timer();
timer.schedule(new TimeOut(), 0, 10000);
GetInfo();
StartPlaySession();
}
public class TimeOut extends TimerTask
{
#Override
public void run() {
EndPlaySession();
GetInfo();
}
}
#Override
public void update(String command) {
if ("RADIO_STARTED".equals(command))
{
this.start();
}
if ("RADIO_STOPPED".equals(command))
{
this.stop();
if (this.currentTrack != null && this.counter.getTrackTime() >= 60)
this.Scrobble();
EndPlaySession();
}
}
private void handleException(String message)
{
try {
String timeStamp = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("/home/pi/OnlineRadio/error_log.txt", true)));
out.println("(" + timeStamp + ") [SCROBBLER] - " + message + "\n\n\r");
out.close();
} catch (IOException e) {}
this.stop();
this.start();
}
}
I create a new instance of Scrobbler in my main method and register it as an observable to player. Once I start the radio, player will notify its observers (including instance of Scrobbler class) by calling update() method and forward "RADIO_STARTED" or "RADIO_STOPPED" (after starting or stopping the radio). As you can see in code, on RADIO_STARTED, a start() method is called where new Thread is started. Starting a new thread is probably unnecessary here since it only starts the timer but it shouldn't be a problem neither. After starting the timer, every 10 seconds method run() in class TimeOut will be called which then calls necessary methods.
This code works but sometimes it just stops for no reason. All other parts of application continue to work (music is still playing, application reacts on buttons etc.), just it doesn't update the song and there's no communication with my website at all so not even one of these methods is called, just like the timer stopped. When I stop and start the radio again or change the station, it works again (as you can see in code, the timer will be stoped every time the radio stops and the timer will start everytime the radio starts), but it will break again after some time.
Since I have a lot of try-catch blocks in those methods with POST requests, at first I thought that there must be an exception occuring and killing the timer thread so I created the handleException() method which logs exception message to a file and restarts this timer (you can see in code), and then I handle exceptions like this, for example:
try {
writer.close();
} catch (IOException e) {
this.handleException(e.getMessage());
}
But when the problem occured again, log file was empty, which means that not even one exception occured. I also tried to log all the data everytime the song changes and everything is fine, it just stops after a while for no reason. And I can't find a regularity in occuring, sometimes it occurs after a few minutes and sometimes if works for hours before it breaks.
This app runs on Raspberry Pi model B, and I don't know if this means something, but it's in JAR and it starts with the Pi (via cron #reboot) since I don't have any monitor nor keyboard/mouse on this Pi, so the app must start with it and run in background all the time. And I use SSH to transfer the JAR to Pi and to read log files.
Somewhere I read that it's not uncommon for the Java timer to stop without any reason. But how to solve this?
I've created my first live wallpaper implementing drawing in a separate thread. So now I have a WallpaperService and my WallpaperPainter who does the job. The problem is that I getting a IllegalArgumentException in unlockCanvasAndPost method on some of devices (Samsung Note is the one). I've read all recomendations I could find but couldn't fix that bug. Seems like the unlockCanvasAndPost is called when surface is destroyed so canvas is invalid. Here is the essential parts of code:
In wallpaper service:
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
super.onSurfaceChanged(holder, format, width, height);
painting.setSurfaceSize(width, height);
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
painting.start();
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
painting.stopPainting();
while (retry) {
try {
painting.join();
retry = false;
} catch (InterruptedException e) { }
}
super.onSurfaceDestroyed(holder);
}
In the painting thread:
public void stopPainting() {
this.run = false;
synchronized(this) {
this.notify();
}
}
public void run() {
this.run = true;
Canvas c = null;
while (run) {
try {
synchronized (this) {
Thread.sleep(50);
c = this.surfaceHolder.lockCanvas();
doDraw(c);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (c != null) {
this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM
}
}
// if pause...
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) { }
}
}
}
}
Can anyone give me any clue what I'm doing wrong? I'm new both for Java and Android.
If error is: UnlockAndPost Failed, it means it unlocked no buffer.
After this.surfaceHolder.unlockCanvasAndPost(c);
you can append
this.surfaceHolder.lockCanvas();
(sorry for my poor English proficiency)
When you open the preview of wallpaper, creates the object WallpaperService and further creates an instance of Engine. Then the stream starts drawing wallpaper.
Then, when you click "Set wallpaper" - a new instance of WallpaperService is not created. But he call the onCreateEngine() method, which returns another (second) instance of Engine. Which also runs its own thread.
Now you have two competing thread!!! So they lead to an exception being thrown.
All you need to do to fix the bug - is to write a correct method onCreateEngine().
replace this:
#Override
public Engine onCreateEngine() {
return new SampleEngine();
}
to this:
private SampleEngine engine;
#Override
public Engine onCreateEngine() {
if (engine!=null) {
engine.painting.stopPainting();
engine = null;
}
engine = new SampleEngine();
return engine;
}
I don't see a definitive problem but here are some thoughts.
There is a chance that you unlock a canvas that has not been locked. I would set c = null; at the top of your while loop otherwise the previous value of c would be unlocked the next time through the loop.
while (run) {
Canvas c = null;
...
Your run field should be marked as volatile because it is accessed by multiple threads.
Never call Thread.sleep(...) inside of a synchronized block. That's a very bad practice since it blocks other threads unnecessarily.
Make sure you at least log your exceptions. Be extremely careful about catch (Exception e) {}. All that does is mask your problems.
There isn't much point in doing the join() inside a while loop. If your thread gets interrupted you should interrupt the painting thread and quit.
Since you are both sleeping and waiting, it would make more sense to remove the sleep and do something like:
try {
synchronized (this) {
if (wait) {
wait();
else {
wait(50);
}
}
} catch (Exception e) {
e.printStackTrace();
}
I had the same problem with my live wallpaper. On a Nexus 5 emulator it runs fine, but when I run it on a Nexus 10 emulator it crashes the moment the app loads.
I found out that the problem was because the default Skin for the emulator has the wrong resolution. After I changed the Skin to "No Skin" then I don't get the crash anymore.
For more information on how to fix the Skin with wrong resolution, please see:
Android Studio - Tablet emulator not showing correct resolution