Multiple downloading display in notification bar and also in activity - android

Right now in my application downloading code is working but when i download multiple files it download randomly not in queue, i need it download in queue and this current download is not displaying in notification bar only display in activity.
I want to know how to possible multiple downloading with displaying in notification bar and also display progress bar in current activity.
Thank you

Looper
By using looper you download multiple file in queue one by one.
Steps 1: Lets create DownloadThreadListener.java interface which will be used to get thread updates.
package com.example.looper;
public interface DownloadThreadListener {
void handleDownloadThreadUpdate();
}
Steps 2: Lets now create a class named DownloadTask.java which will simulate the downloading. We will be using random time sleep to simulate the download time.
package com.example.looper;
import java.util.Random;
import android.util.Log;
/**
* This is not a real download task. It just sleeps for some random time when
* it's launched. The idea is not to require a connection and not to eat it.
*
*/
public class DownloadTask implements Runnable {
private static final String TAG = DownloadTask.class.getSimpleName();
private static final Random random = new Random();
private int lengthSec;
public DownloadTask() {
lengthSec = random.nextInt(3) + 1;
}
#Override
public void run() {
try {
Thread.sleep(lengthSec * 1000);
// it's a good idea to always catch Throwable
// in isolated "codelets" like Runnable or Thread
// otherwise the exception might be sunk by some
// agent that actually runs your Runnable - you
// never know what it might be.
} catch (Throwable t) {
Log.e(TAG, "Error in DownloadTask", t);
}
}
}
Steps 3: Now lets create the thread subclass which will act as pipeline. First we will call Looper.prepare() to make this Thread act as pipeline. Next new Handler() will be called to handle message queue on this thread. Finally Looper.loop() will be called to start running the message loop. New tasks will be added using enqueueDownload(final DownloadTask task).
package com.example.looper;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
public final class DownloadThread extends Thread {
private static final String TAG = DownloadThread.class.getSimpleName();
private Handler handler;
private int totalQueued;
private int totalCompleted;
private DownloadThreadListener listener;
public DownloadThread(DownloadThreadListener listener) {
this.listener = listener;
}
#Override
public void run() {
try {
// preparing a looper on current thread
// the current thread is being detected implicitly
Looper.prepare();
Log.i(TAG, "DownloadThread entering the loop");
// now, the handler will automatically bind to the
// Looper that is attached to the current thread
// You don't need to specify the Looper explicitly
handler = new Handler();
// After the following line the thread will start
// running the message loop and will not normally
// exit the loop unless a problem happens or you
// quit() the looper (see below)
Looper.loop();
Log.i(TAG, "DownloadThread exiting gracefully");
} catch (Throwable t) {
Log.e(TAG, "DownloadThread halted due to an error", t);
}
}
// This method is allowed to be called from any thread
public synchronized void requestStop() {
// using the handler, post a Runnable that will quit()
// the Looper attached to our DownloadThread
// obviously, all previously queued tasks will be executed
// before the loop gets the quit Runnable
handler.post(new Runnable() {
#Override
public void run() {
// This is guaranteed to run on the DownloadThread
// so we can use myLooper() to get its looper
Log.i(TAG, "DownloadThread loop quitting by request");
Looper.myLooper().quit();
}
});
}
public synchronized void enqueueDownload(final DownloadTask task) {
// Wrap DownloadTask into another Runnable to track the statistics
handler.post(new Runnable() {
#Override
public void run() {
try {
task.run();
} finally {
// register task completion
synchronized (DownloadThread.this) {
totalCompleted++;
}
// tell the listener something has happened
signalUpdate();
}
}
});
totalQueued++;
// tell the listeners the queue is now longer
signalUpdate();
}
public synchronized int getTotalQueued() {
return totalQueued;
}
public synchronized int getTotalCompleted() {
return totalCompleted;
}
// Please note! This method will normally be called from the download
// thread.
// Thus, it is up for the listener to deal with that (in case it is a UI
// component,
// it has to execute the signal handling code in the UI thread using Handler
// - see
// DownloadQueueActivity for example).
private void signalUpdate() {
if (listener != null) {
listener.handleDownloadThreadUpdate();
}
}
}
Steps 4: Now add full functionality to MainActivity.java . Here also we will create handler so that we can post events on main thread.
package com.example.looper;
import java.util.Random;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends Activity implements DownloadThreadListener,
OnClickListener {
private DownloadThread downloadThread;
private Handler handler;
private ProgressBar progressBar;
private TextView statusText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create and launch the download thread
downloadThread = new DownloadThread(this);
downloadThread.start();
// Create the Handler. It will implicitly bind to the Looper
// that is internally created for this thread (since it is the UI
// thread)
handler = new Handler();
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
statusText = (TextView) findViewById(R.id.status_text);
Button scheduleButton = (Button) findViewById(R.id.schedule_button);
scheduleButton.setOnClickListener(this);
}
#Override
protected void onDestroy() {
super.onDestroy();
// request the thread to stop
downloadThread.requestStop();
}
// note! this might be called from another thread
#Override
public void handleDownloadThreadUpdate() {
// we want to modify the progress bar so we need to do it from the UI
// thread
// how can we make sure the code runs in the UI thread? use the handler!
handler.post(new Runnable() {
#Override
public void run() {
int total = downloadThread.getTotalQueued();
int completed = downloadThread.getTotalCompleted();
progressBar.setMax(total);
progressBar.setProgress(0); // need to do it due to a
// ProgressBar bug
progressBar.setProgress(completed);
statusText.setText(String.format("Downloaded %d/%d", completed,
total));
// vibrate for fun
if (completed == total) {
((Vibrator) getSystemService(VIBRATOR_SERVICE))
.vibrate(100);
}
}
});
}
#Override
public void onClick(View source) {
if (source.getId() == R.id.schedule_button) {
int totalTasks = new Random().nextInt(3) + 1;
for (int i = 0; i < totalTasks; ++i) {
downloadThread.enqueueDownload(new DownloadTask());
}
}
}
}
Steps 5: Add Vibrate permission
<uses-permission android:name="android.permission.VIBRATE" />
Original Post Complete tutorial here.

Related

Can I pause a program for a while? [duplicate]

I want to make a pause between two lines of code, Let me explain a bit:
-> the user clicks a button (a card in fact) and I show it by changing the background of this button:
thisbutton.setBackgroundResource(R.drawable.icon);
-> after let's say 1 second, I need to go back to the previous state of the button by changing back its background:
thisbutton.setBackgroundResource(R.drawable.defaultcard);
-> I've tried to pause the thread between these two lines of code with:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
However, this does not work. Maybe it's the process and not the Thread that I need to pause?
I've also tried (but it doesn't work):
new Reminder(5);
With this:
public class Reminder {
Timer timer;
public Reminder(int seconds) {
timer = new Timer();
timer.schedule(new RemindTask(), seconds*1000);
}
class RemindTask extends TimerTask {
public void run() {
System.out.format("Time's up!%n");
timer.cancel(); //Terminate the timer thread
}
}
}
How can I pause/sleep the thread or process?
One solution to this problem is to use the Handler.postDelayed() method. Some Google training materials suggest the same solution.
#Override
public void onClick(View v) {
my_button.setBackgroundResource(R.drawable.icon);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
}, 2000);
}
However, some have pointed out that the solution above causes a memory leak because it uses a non-static inner and anonymous class which implicitly holds a reference to its outer class, the activity. This is a problem when the activity context is garbage collected.
A more complex solution that avoids the memory leak subclasses the Handler and Runnable with static inner classes inside the activity since static inner classes do not hold an implicit reference to their outer class:
private static class MyHandler extends Handler {}
private final MyHandler mHandler = new MyHandler();
public static class MyRunnable implements Runnable {
private final WeakReference<Activity> mActivity;
public MyRunnable(Activity activity) {
mActivity = new WeakReference<>(activity);
}
#Override
public void run() {
Activity activity = mActivity.get();
if (activity != null) {
Button btn = (Button) activity.findViewById(R.id.button);
btn.setBackgroundResource(R.drawable.defaultcard);
}
}
}
private MyRunnable mRunnable = new MyRunnable(this);
public void onClick(View view) {
my_button.setBackgroundResource(R.drawable.icon);
// Execute the Runnable in 2 seconds
mHandler.postDelayed(mRunnable, 2000);
}
Note that the Runnable uses a WeakReference to the Activity, which is necessary in a static class that needs access to the UI.
You can try this one it is short
SystemClock.sleep(7000);
WARNING: Never, ever, do this on a UI thread.
Use this to sleep eg. background thread.
Full solution for your problem will be:
This is available API 1
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View button) {
button.setBackgroundResource(R.drawable.avatar_dead);
final long changeTime = 1000L;
button.postDelayed(new Runnable() {
#Override
public void run() {
button.setBackgroundResource(R.drawable.avatar_small);
}
}, changeTime);
}
});
Without creating tmp Handler. Also this solution is better than #tronman because we do not retain view by Handler.
Also we don't have problem with Handler created at bad thread ;)
Documentation
public static void sleep (long ms)
Added in API level 1
Waits a given number of milliseconds (of uptimeMillis) before returning. Similar to sleep(long), but does not throw InterruptedException; interrupt() events are deferred until the
next interruptible operation.
Does not return until at least the specified number of milliseconds has elapsed.
Parameters
ms to sleep before returning, in milliseconds of uptime.
Code for postDelayed from View class:
/**
* <p>Causes the Runnable to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the user interface thread.</p>
*
* #param action The Runnable that will be executed.
* #param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* #return true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* #see #post
* #see #removeCallbacks
*/
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
return true;
}
I use this:
Thread closeActivity = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
// Do some stuff
} catch (Exception e) {
e.getLocalizedMessage();
}
}
});
I use CountDownTime
new CountDownTimer(5000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
// do something after 1s
}
#Override
public void onFinish() {
// do something end times 5s
}
}.start();
You probably don't want to do it that way. By putting an explicit sleep() in your button-clicked event handler, you would actually lock up the whole UI for a second. One alternative is to use some sort of single-shot Timer. Create a TimerTask to change the background color back to the default color, and schedule it on the Timer.
Another possibility is to use a Handler. There's a tutorial about somebody who switched from using a Timer to using a Handler.
Incidentally, you can't pause a process. A Java (or Android) process has at least 1 thread, and you can only sleep threads.
This is what I did at the end of the day - works fine now :
#Override
public void onClick(View v) {
my_button.setBackgroundResource(R.drawable.icon);
// SLEEP 2 SECONDS HERE ...
final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
});
}
}, 2000);
}
In addition to Mr. Yankowsky's answers, you could also use postDelayed(). This is available on any View (e.g., your card) and takes a Runnable and a delay period. It executes the Runnable after that delay.
This is my example
Create a Java Utils
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
public class Utils {
public static void showDummyWaitingDialog(final Context context, final Intent startingIntent) {
// ...
final ProgressDialog progressDialog = ProgressDialog.show(context, "Please wait...", "Loading data ...", true);
new Thread() {
public void run() {
try{
// Do some work here
sleep(5000);
} catch (Exception e) {
}
// start next intent
new Thread() {
public void run() {
// Dismiss the Dialog
progressDialog.dismiss();
// start selected activity
if ( startingIntent != null) context.startActivity(startingIntent);
}
}.start();
}
}.start();
}
}
Or you could use:
android.os.SystemClock.sleep(checkEvery)
which has the advantage of not requiring a wrapping try ... catch.
If you use Kotlin and coroutines, you can simply do
GlobalScope.launch {
delay(3000) // In ms
//Code after sleep
}
And if you need to update UI
GlobalScope.launch {
delay(3000)
GlobalScope.launch(Dispatchers.Main) {
//Action on UI thread
}
}
I know this is an old thread, but in the Android documentation I found a solution that worked very well for me...
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
https://developer.android.com/reference/android/os/CountDownTimer.html
Hope this helps someone...
class MyActivity{
private final Handler handler = new Handler();
private Runnable yourRunnable;
protected void onCreate(#Nullable Bundle savedInstanceState) {
// ....
this.yourRunnable = new Runnable() {
#Override
public void run() {
//code
}
};
this.handler.postDelayed(this.yourRunnable, 2000);
}
#Override
protected void onDestroy() {
// to avoid memory leaks
this.handler.removeCallbacks(this.yourRunnable);
}
}
And to be double sure you can be combined it with the "static class" method as described in the tronman answer

How to pause activity with threads and resume afterwards - android

I have tried some ways to do it and didn't secced.
I have MainActivity which start 3 thread. I want to stop the threads when the user press "back" bottum or when from some reason the app stop (phone call for example).
and after the activity again seen (when the user come back to the app) the thread will continue from where they stop.
All the threads defined in MainActivity and there they start.
Thanks!
public class MainActivity extends Activity
{
//threads
private PingPongGame gameThread;
private PaddleMover paddleMoverThread;
private PresentThread giftThread;
public GameSounds gameSounds;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
gameLevel = new GameLevel0(screenWidth , screenHeight, this.giftArr);
gameLevelView = new GameLevelView(this,gameLevel);
// Creating the game view
this.gameView = new PingPongView(this);
// Setting the gameView as the main view for the PingPong activity.
setContentView(gameView);
if(gameThread == null){
//create the main thread
gameThread = new PingPongGame( gamePaddle, gameView, gameLevel , message , ballArr , gameSounds);
//create the thread responsible for moving the paddle
paddleMoverThread = new PaddleMover(gamePaddle, gameView);
//create the thread responsible for present
giftThread = new PresentThread(gamePaddle , gameView , gameLevel, message , giftArr , ballArr,gameSounds );
gameThread.start();
paddleMoverThread.start();
giftThread.start();
}
}
//This method is automatically called when the user touches the screen
#Override
public boolean onTouchEvent(MotionEvent event)
{
float destination;
// Toast.makeText(this, "try!", Toast.LENGTH_SHORT).show();
//get the x coordinate of users' press
destination = event.getX();
//notify the paddle mover thread regarding the new destination
gamePaddle.setPaddleDestination(destination);
return true;
}
}
Example of one of my threads:
public class PaddleMover extends Thread
{
private Tray gamePaddle; //holds a reference to the paddle
private PingPongView gameView; //holds a reference to the main view
//for stop
private Object mPauseLock;
private boolean mPaused;
//initialize class variables
public PaddleMover(Tray thePaddle, PingPongView mainView)
{
gamePaddle = thePaddle;
gameView = mainView;
//for stop and resume threads
mPauseLock = new Object();
mPaused = false;
}
//main method of the current thread
#Override
public void run()
{
//infinitely loop, and move the paddle if necessary
while ((Const.isLose == false) && (Const.isCompleteThisLevel==false) && (Const.isDestroy == false))
{
//check whether the paddle should be moved
if (gamePaddle.getMiddle() != gamePaddle.getPaddleDestination())
{
//move the paddle
gamePaddle.move();
//send a request to refresh the display
gameView.postInvalidate();
}
try
{
PaddleMover.sleep(3);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
//for stop and resume
synchronized (mPauseLock) {
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
}
}
}
}
}
/**
* Call this on pause.
*/
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
/**
* Call this on resume.
*/
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
}
You can achieve a lot better control with your threads using Runnable objects. Instead of defining your logic using a loop within the run() method, do the following:
Define your framewise logic for each thread within Runnable objects. Override the run() method. Do not use a while loop within your Runnable.
Create a variable which tracks whether or not your game is paused. Use this variable to create a single while() loop within a main thread.
Define a Thread class and get it's Handler. You can do this like so:
class WorkerThread extends Thread
{
private volatile Handler mHandler;
//volatile so you can try to acquire it until it is instantiated
#Override
public void run()
{
//This is pretty much boilerplate for worker thread implementations
Looper.prepare();
//Handlers must be instantiated by their respective threads
mHandler = new Handler();
Looper.loop();
}
#Override
public Handler getHandler()
{
return mHandler;
}
}
Instantiate multiple WorkerThreads and acquire references to their Handler objects.
In each frame, pass the Runnable() which defines the logic you want the Thread to execute to the Handler using the postRunnable() method.
Use ConditionVariable objects to make sure you don't call the postRunnable() method while the WorkerThread is still executing.
Runnable thread1runnable = new Runnable()
{
#Override
public void run()
{
//Do your logic here
...
thread1finished.open(); //This lets the block() function return
}
}
ConditionVariable thread1finished = new ConditionVariable();
thread1finished.open(); //Make sure the loop doesn't block the first time through
Thread thread1 = new WorkerThread();
//Start the thread to acquire the handler and prepare it for looping
thread1.start();
//Call stop() when shutting down your game, not pausing
Handler thread1handler;
while (thread1handler != null)
thread1handler = thread1.getHandler();
//A crude way of making sure you acquire the instantiated handler, you can top this
while (gameRunning)
{
if (!isPaused) //Stops work when your isPaused variable is set
{
thread1finished.block(); //Wait for the last runnable to finish
//Lock the ConditionVariable so the loop will block
thread1finished.close();
//Signal the worker thread to start crunching
thread1handler.postRunnable(thread1runnable);
}
}
In your onPause() override, set the variable that stops your while() loop from posting the Runnable objects to your WorkerThreads. Enjoy automatic starting and stopping!
There may be issues adapting this method to three different threads which you don't want to synchronize frame-per-frame. Let me know how it goes.

Android transistions not working

I have a start screen with a short delay, after the delay it moves onto the splashscreen however I cant seem to override the transition and I cant see why...Although the transition does work in debug mode which is very strange
package com.example.android.bubblestrouble;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class Team extends Activity{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
final int delay = 3000;
setContentView(R.layout.team);
Thread welcomeThread = new Thread()
{
int wait = 0;
#Override
public void run()
{
try {
super.run();
/**
* use while to get the splash time. Use sleep() to increase
* the wait variable for every 100L.
*/
while (wait < delay)
{
sleep(100);
wait += 100;
}
}
catch (Exception e)
{
System.out.println("EXc=" + e);
}
finally
{
/**
* Called after splash times up. Do some action after splash
* times up. Here we moved to another main activity class
*/
startActivity(new Intent(Team.this, SplashScreen.class));
Team.this.finish();
Team.this.overridePendingTransition(R.anim.fade, R.anim.hold);
}
}
};
welcomeThread.start();
}
}
Straight solution. Show your splash image immediately on activity start and replace in with the needed layout by timer. Something like this(onCreate event of Team activity):
ImageView splashImage = new ImageView(this);
splashImage.setImageBitmap(splashBitmap); // or drawable/resource - as you like
setContentView(splashImage);
Thread timerThread = new Thread() {
#Override
public void run() {
sleep(3000);
Team.runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(R.layout.team);
}
});
}
}
timerThread.start();

Repeat a task with a time delay?

I have a variable in my code say it is "status".
I want to display some text in the application depending on this variable value. This has to be done with a specific time delay.
It's like,
Check status variable value
Display some text
Wait for 10 seconds
Check status variable value
Display some text
Wait for 15 seconds
and so on. The time delay may vary and it is set once the text is displayed.
I have tried Thread.sleep(time delay) and it failed. Any better way to get this done?
You should use Handler's postDelayed function for this purpose. It will run your code with specified delay on the main UI thread, so you will be able to update UI controls.
private int mInterval = 5000; // 5 seconds by default, can be changed later
private Handler mHandler;
#Override
protected void onCreate(Bundle bundle) {
// your code here
mHandler = new Handler();
startRepeatingTask();
}
#Override
public void onDestroy() {
super.onDestroy();
stopRepeatingTask();
}
Runnable mStatusChecker = new Runnable() {
#Override
public void run() {
try {
updateStatus(); //this function can change value of mInterval.
} finally {
// 100% guarantee that this always happens, even if
// your update method throws an exception
mHandler.postDelayed(mStatusChecker, mInterval);
}
}
};
void startRepeatingTask() {
mStatusChecker.run();
}
void stopRepeatingTask() {
mHandler.removeCallbacks(mStatusChecker);
}
To anyone interested, here's a class I created using inazaruk's code that creates everything needed (I called it UIUpdater because I use it to periodically update the UI, but you can call it anything you like):
import android.os.Handler;
/**
* A class used to perform periodical updates,
* specified inside a runnable object. An update interval
* may be specified (otherwise, the class will perform the
* update every 2 seconds).
*
* #author Carlos Simões
*/
public class UIUpdater {
// Create a Handler that uses the Main Looper to run in
private Handler mHandler = new Handler(Looper.getMainLooper());
private Runnable mStatusChecker;
private int UPDATE_INTERVAL = 2000;
/**
* Creates an UIUpdater object, that can be used to
* perform UIUpdates on a specified time interval.
*
* #param uiUpdater A runnable containing the update routine.
*/
public UIUpdater(final Runnable uiUpdater) {
mStatusChecker = new Runnable() {
#Override
public void run() {
// Run the passed runnable
uiUpdater.run();
// Re-run it after the update interval
mHandler.postDelayed(this, UPDATE_INTERVAL);
}
};
}
/**
* The same as the default constructor, but specifying the
* intended update interval.
*
* #param uiUpdater A runnable containing the update routine.
* #param interval The interval over which the routine
* should run (milliseconds).
*/
public UIUpdater(Runnable uiUpdater, int interval){
UPDATE_INTERVAL = interval;
this(uiUpdater);
}
/**
* Starts the periodical update routine (mStatusChecker
* adds the callback to the handler).
*/
public synchronized void startUpdates(){
mStatusChecker.run();
}
/**
* Stops the periodical update routine from running,
* by removing the callback.
*/
public synchronized void stopUpdates(){
mHandler.removeCallbacks(mStatusChecker);
}
}
You can then create a UIUpdater object inside your class and use it like so:
...
mUIUpdater = new UIUpdater(new Runnable() {
#Override
public void run() {
// do stuff ...
}
});
// Start updates
mUIUpdater.startUpdates();
// Stop updates
mUIUpdater.stopUpdates();
...
If you want to use this as an activity updater, put the start call inside the onResume() method and the stop call inside the onPause(), so the updates start and stop according to the activity visibility.
I think the new hotness is to use a ScheduledThreadPoolExecutor. Like so:
private final ScheduledThreadPoolExecutor executor_ =
new ScheduledThreadPoolExecutor(1);
this.executor_.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
update();
}
}, 0L, kPeriod, kTimeUnit);
There are 3 ways to do it:
Use ScheduledThreadPoolExecutor
A bit of overkill since you don't need a pool of Thread
//----------------------SCHEDULER-------------------------
private final ScheduledThreadPoolExecutor executor_ =
new ScheduledThreadPoolExecutor(1);
ScheduledFuture<?> schedulerFuture;
public void startScheduler() {
schedulerFuture= executor_.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
//DO YOUR THINGS
pageIndexSwitcher.setVisibility(View.GONE);
}
}, 0L, 5*MILLI_SEC, TimeUnit.MILLISECONDS);
}
public void stopScheduler() {
pageIndexSwitcher.setVisibility(View.VISIBLE);
schedulerFuture.cancel(false);
startScheduler();
}
Use Timer Task
Old Android Style
//----------------------TIMER TASK-------------------------
private Timer carousalTimer;
private void startTimer() {
carousalTimer = new Timer(); // At this line a new Thread will be created
carousalTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//DO YOUR THINGS
pageIndexSwitcher.setVisibility(INVISIBLE);
}
}, 0, 5 * MILLI_SEC); // delay
}
void stopTimer() {
carousalTimer.cancel();
}
Use Handler and Runnable
Modern Android Style
//----------------------HANDLER-------------------------
private Handler taskHandler = new android.os.Handler();
private Runnable repeatativeTaskRunnable = new Runnable() {
public void run() {
//DO YOUR THINGS
}
};
void startHandler() {
taskHandler.postDelayed(repeatativeTaskRunnable, 5 * MILLI_SEC);
}
void stopHandler() {
taskHandler.removeCallbacks(repeatativeTaskRunnable);
}
Non-Leaky Handler with Activity / Context
Declare an inner Handler class which does not leak Memory in your Activity/Fragment class
/**
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
*/
private static class NonLeakyHandler extends Handler {
private final WeakReference<FlashActivity> mActivity;
public NonLeakyHandler(FlashActivity activity) {
mActivity = new WeakReference<FlashActivity>(activity);
}
#Override
public void handleMessage(Message msg) {
FlashActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
Declare a runnable which will perform your repetitive task in your Activity/Fragment class
private Runnable repeatativeTaskRunnable = new Runnable() {
public void run() {
new Handler(getMainLooper()).post(new Runnable() {
#Override
public void run() {
//DO YOUR THINGS
}
};
Initialize Handler object in your Activity/Fragment (here FlashActivity is my activity class)
//Task Handler
private Handler taskHandler = new NonLeakyHandler(FlashActivity.this);
To repeat a task after fix time interval
taskHandler.postDelayed(repeatativeTaskRunnable , DELAY_MILLIS);
To stop the repetition of task
taskHandler .removeCallbacks(repeatativeTaskRunnable );
UPDATE: In Kotlin:
//update interval for widget
override val UPDATE_INTERVAL = 1000L
//Handler to repeat update
private val updateWidgetHandler = Handler()
//runnable to update widget
private var updateWidgetRunnable: Runnable = Runnable {
run {
//Update UI
updateWidget()
// Re-run it after the update interval
updateWidgetHandler.postDelayed(updateWidgetRunnable, UPDATE_INTERVAL)
}
}
// SATART updating in foreground
override fun onResume() {
super.onResume()
updateWidgetHandler.postDelayed(updateWidgetRunnable, UPDATE_INTERVAL)
}
// REMOVE callback if app in background
override fun onPause() {
super.onPause()
updateWidgetHandler.removeCallbacks(updateWidgetRunnable);
}
Timer works fine. Here, I use Timer to search text after 1.5s and update UI. Hope that helps.
private Timer _timer = new Timer();
_timer.schedule(new TimerTask() {
#Override
public void run() {
// use runOnUiThread(Runnable action)
runOnUiThread(new Runnable() {
#Override
public void run() {
search();
}
});
}
}, timeInterval);
Using kotlin and its Coroutine its quite easy, first declare a job in your class (better in your viewModel) like this:
private var repeatableJob: Job? = null
then when you want to create and start it do this:
repeatableJob = viewModelScope.launch {
while (isActive) {
delay(5_000)
loadAlbums(iImageAPI, titleHeader, true)
}
}
repeatableJob?.start()
and if you want to finish it:
repeatableJob?.cancel()
PS: viewModelScope is only available in view models, you can use other Coroutine scopes such as withContext(Dispatchers.IO)
More information: Here
Timer is another way to do your work but be quiet sure to add runOnUiThread if you are working with UI.
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.app.Activity;
public class MainActivity extends Activity {
CheckBox optSingleShot;
Button btnStart, btnCancel;
TextView textCounter;
Timer timer;
MyTimerTask myTimerTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
optSingleShot = (CheckBox)findViewById(R.id.singleshot);
btnStart = (Button)findViewById(R.id.start);
btnCancel = (Button)findViewById(R.id.cancel);
textCounter = (TextView)findViewById(R.id.counter);
btnStart.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
if(timer != null){
timer.cancel();
}
//re-schedule timer here
//otherwise, IllegalStateException of
//"TimerTask is scheduled already"
//will be thrown
timer = new Timer();
myTimerTask = new MyTimerTask();
if(optSingleShot.isChecked()){
//singleshot delay 1000 ms
timer.schedule(myTimerTask, 1000);
}else{
//delay 1000ms, repeat in 5000ms
timer.schedule(myTimerTask, 1000, 5000);
}
}});
btnCancel.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
if (timer!=null){
timer.cancel();
timer = null;
}
}
});
}
class MyTimerTask extends TimerTask {
#Override
public void run() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
final String strDate = simpleDateFormat.format(calendar.getTime());
runOnUiThread(new Runnable(){
#Override
public void run() {
textCounter.setText(strDate);
}});
}
}
}
and xml is...
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<CheckBox
android:id="#+id/singleshot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Single Shot"/>
Another Way to use CountDownTimer
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
Schedule a countdown until a time in the future, with regular notifications on intervals along the way. Example of showing a 30 second countdown in a text field:
For Details
Try following example it works !!!
Use [Handler] in onCreate() method which makes use of postDelayed() method that Causes the Runnable to be added to the message queue, to be run after the specified amount of time elapses that is 0 in given example. 1
Refer this code :
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//------------------
//------------------
android.os.Handler customHandler = new android.os.Handler();
customHandler.postDelayed(updateTimerThread, 0);
}
private Runnable updateTimerThread = new Runnable()
{
public void run()
{
//write here whaterver you want to repeat
customHandler.postDelayed(this, 1000);
}
};
You can use a Handler to post runnable code. This technique is outlined very nicely here: https://guides.codepath.com/android/Repeating-Periodic-Tasks
Based on the above post concerning the ScheduledThreadPoolExecutor, I came up with a utility that suited my needs (wanted to fire a method every 3 seconds):
class MyActivity {
private ScheduledThreadPoolExecutor mDialogDaemon;
private void initDebugButtons() {
Button btnSpawnDialogs = (Button)findViewById(R.id.btn_spawn_dialogs);
btnSpawnDialogs.setVisibility(View.VISIBLE);
btnSpawnDialogs.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
spawnDialogs();
}
});
}
private void spawnDialogs() {
if (mDialogDaemon != null) {
mDialogDaemon.shutdown();
mDialogDaemon = null;
}
mDialogDaemon = new ScheduledThreadPoolExecutor(1);
// This process will execute immediately, then execute every 3 seconds.
mDialogDaemon.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Do something worthwhile
}
});
}
}, 0L, 3000L, TimeUnit.MILLISECONDS);
}
}
In my case, I had to execute a process if one of these conditions were true: if a previous process was completed or if 5 seconds had already passed. So, I did the following and worked pretty well:
private Runnable mStatusChecker;
private Handler mHandler;
class {
method() {
mStatusChecker = new Runnable() {
int times = 0;
#Override
public void run() {
if (times < 5) {
if (process1.isRead()) {
executeProcess2();
} else {
times++;
mHandler.postDelayed(mStatusChecker, 1000);
}
} else {
executeProcess2();
}
}
};
mHandler = new Handler();
startRepeatingTask();
}
void startRepeatingTask() {
mStatusChecker.run();
}
void stopRepeatingTask() {
mHandler.removeCallbacks(mStatusChecker);
}
}
If process1 is read, it executes process2. If not, it increments the variable times, and make the Handler be executed after one second. It maintains a loop until process1 is read or times is 5. When times is 5, it means that 5 seconds passed and in each second, the if clause of process1.isRead() is executed.
For people using Kotlin, inazaruk's answer will not work, the IDE will require the variable to be initialized, so instead of using the postDelayed inside the Runnable, we'll use it in an separate method.
Initialize your Runnable like this :
private var myRunnable = Runnable {
//Do some work
//Magic happens here ↓
runDelayedHandler(1000) }
Initialize your runDelayedHandler method like this :
private fun runDelayedHandler(timeToWait : Long) {
if (!keepRunning) {
//Stop your handler
handler.removeCallbacksAndMessages(null)
//Do something here, this acts like onHandlerStop
}
else {
//Keep it running
handler.postDelayed(myRunnable, timeToWait)
}
}
As you can see, this approach will make you able to control the lifetime of the task, keeping track of keepRunning and changing it during the lifetime of the application will do the job for you.

Android: Two or more threads? (Program is working)

I have created a sample/demo/test program in Android that runs quite nicely, if you see below you will see I have created a thread. Now I want to create another thread to work with another handler... since I cannot have two run() methods... how do I do this?
This is my (working - no errors) program:
package com.ryan1;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
public class main extends Activity implements Runnable{
int level = 0;
int seconds_running=0;
TextView the_seconds,the_level;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
the_seconds = (TextView) findViewById(R.id.textview_seconds);
the_level = (TextView) findViewById(R.id.textview_level);
Thread thread = new Thread(this);
Thread thread2 = new Thread(this);
thread.start();
thread2.start();
}
public void run() {
while(seconds_running<500)
{
if(seconds_running %5 ==0){level++;}
try {
handler.sendEmptyMessage(0);
int a = 1000 - (level*100);
if(a<=100){a=25;}
Thread.sleep(a);
System.out.println("R "+Thread.currentThread());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
seconds_running++;
int a = 1000 - (level*100);
the_seconds.setText(" "+seconds_running);
the_level.setText(level+" "+a);
}
};
}
Use anonymous class like this.
Thread thread2 = new Thread( new Runnable() {
public void run() {
// code here with your new handler
}
});
make two inner classes that extends Thread.
create an object for both the classes and call start on those objects.
You are suggesting that you want two runnables, yet you only have one runnable defined, which is your 'main' class. So what you need to do is make two different runnables, so that each can have their own code that can be run.
I would make two new classes, lets say, Runnable1 and Runnable2. I would have both of them implement the runnable interface. Each one of them can then contain different code to run in a separate thread.
Finally, I would change your thread creation/start code to look like this:
Thread thread = new Thread(new Runnable1());
Thread thread2 = new Thread(new Runnable2());
thread.start();
thread2.start();

Categories

Resources