I have a UI thread(MainActivity) calling an AsynTask object(DownloadManager), which, in turn calls 3 threads (DownloaderThread).
How do I pause/resume the 3 DownloaderThreads without pausing the AsynTask or the UI thread?
Following is the code I have currently implemented for the pause functionality, but when the Pause button is clicked, the app crashes with the dialog: "app has stopped". Code:
DownloadManager (AsynTask):
public void onPause() {
try{
t0.wait();
t1.wait();
t2.wait();
this.wait();
}catch (InterruptedException ex){
}
}
DownloaderThread (implements Runnable and is passed to a Thread instance in DownloadManager:
public class DownloaderThread implements Runnable {
private Object mPauseLock;
private Boolean mPaused;
private Boolean mFinished;
public void run(){
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
try{
while(!mFinished){
//do something
synchronized (mPauseLock){
while (mPaused){
try{
mPauseLock.wait();
}catch (InterruptedException e){
}
}
}
}
}
}
public void onPause(){
synchronized (mPauseLock){
mPaused = true;
}
}
You can't really pause an AsyncTask once it started. You can, however, store the progress when activity is paused/destroyed and start from the progress once you are back to the original Activity. But I recommend the best way to complete task for your scenario is to use Service.
Related
I have a method in which I want a delay of a second, and while the delay is running there should be a loading animation (ProgressBar).
Right now, when the method is now running the loading animation is not appearing. If I do not call the Timeout it does appear, and when I do not make it invisible after, it shows up after the timeout.
How do I show the loading animation while the timeout is running? I have a similar problem trying to do with with Thread.sleep(1000).
public void firstMethod(){
ProgressBar pgLoading = (ProgressBar) findViewById(R.id.pgLoading);
pgLoading.setVisibility(VISIBLE);
try {
TimeUnit.SECONDS.sleep(1);
}catch(InterruptionException ex){
ex.printStackTrace();
}
pgLoading.setVisibility(INVISIBLE);
}
By calling the sleep method you are making the UI thread sleep for 1 second during that time nothing will happen on UI Thread hence you do not see the ProgressBar. You should instead use a TimerTask to wait for this one second and then close the ProgressBar.
Checkout this link on how to use TimerTask.
Main thread can't be blocked. That will cause the entire rendering to stop. That's why you only see the result after that timeout.
These kind of operations shoud be handled in other threads. If you are using Java you can use Runnables but you should consider moving to Kotlin to use coroutines.
E.G:
pgLoading.setVisibility(VISIBLE);
new Thread() {
public void run() {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
pgLoading.setVisibility(INVISIBLE);
}
});
}
}
}.start();
This is happening because the current thread is being paused.To avoid this put your delay/long process in a different thread.For example:
public void firstMethod(){
ProgressBar pgLoading = (ProgressBar) findViewById(R.id.pgLoading);
pgLoading.setVisibility(View.VISIBLE);
new Thread(()->{
// Do all your long process here
try {
TimeUnit.SECONDS.sleep(1);
}catch( InterruptedException ex){
ex.printStackTrace();
}
runOnUiThread(() -> pgLoading.setVisibility(View.INVISIBLE));
}).start();
}
I have started the Thread, In that thread i am trying to connect to the server, After receiving the response, I have to update the UI with event listeners(implemented through Interface). Here After receiving the response i need to show the popup Dialog once user clicks OK, need to continue the thread and complete the other process.
class ConnectionThread extends Thread {
ConnectionThread() {
this.setName("ConnectionThread");
}
#Override
public void run() {
// Need to pause the thread for sometime, Need to do the functionality here.
((Activity)mContext).runOnUiThread(new Runnable() {
public void run() {
// custom dialog
showAlertDialog();
// start the thread functionality again from that position.
}
});
}
I have tried with wait() concept and also join, which are not helped as expected. Any help appreciated.
you can use countdownlatch
class ConnectionThread extends Thread {
CountDownLatch countDownLatch = new CountDownLatch(1);
public ConnectionThread() {
this.setName("ConnectionThread");
}
#Override
public void run() {
try {
sleep(2000);
runOnUiThread(new Runnable() {
#Override
public void run() {
//update ui then
countDownLatch.countDown();
}
});
countDownLatch.await();
//start process again
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
In the below code I am trying to run a thread when a button is clicked. In the button listener I create a new thread and run it...but at run time, when the button is pressed, the button itself freezes and the app does not respond and I receive ANR dialog. Moreover, when the socket is connected successfully even the TexView
mtvStatus.setText("RFC-SOCKET CONNECTED");
displays nothing.
Please let me know why this is happening.
button listener:
this.mbtnConnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
BluetoothSocket rfcSocket = mSPPCtrl.rfcConnect();
if (rfcSocket.isConnected()) {
mtvStatus.setText("RFC-SOCKET CONNECTED");
Thread rx = new Thread(new RxRun(rfcSocket));
rx.run();
} else {
mtvStatus.setText("RFC-SOCKET NOT CONNECTED");
}
}
});
runnable class
private class RxRun implements Runnable {
private BluetoothSocket mRFCSocket = null;
private OutputStream mRFCOS = null;
private InputStream mRFCIS = null;
public RxRun(BluetoothSocket rfcSocket) {
this.mRFCSocket = rfcSocket;
try {
this.mRFCOS = rfcSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
this.mRFCIS = rfcSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
try {
this.mRFCOS.write(DIRON.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
while (this.mRFCSocket.isConnected()) {
try {
int readBytes = this.mRFCIS.read(new byte[5120]);
Log.d(TAG, CSubTag.bullet("RxRun", "readBytes:" + readBytes));
//mtvRx.setText(""+readBytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
...when the button is pressed, the button itself freezes and the app does not respond and I receive ANR dialog. Moreover, when the socket is connected successfully even the TexView displays nothing.
It's expected, because you haven't actually started the rx thread. Here is what is going on:
mSPPCtrl gets connected,
mtvStatus's text is set to "RFC-SOCKET CONNECTED", but you cannot visually see it because
run() method of the RxRun instance is called manually where the loop while (this.mRFCSocket.isConnected()) may last as long as the socket is connected.
All the above said is invoked on UI-thread and that's the reason of ANR.
You should not call run() manually. Start the rx thread with
rx.start();
Also I highly recommend to move all the rfcSocket logic inside of the thread and notify the UI-thread on success/failure of connection.
EDIT
Here is one the option mentioned in my comment.
Start the rx thread on a button click
this.mbtnConnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(new RxRun(rfcSocket)).start();
}
});
Move your logic inside of the run() method:
public void run() {
BluetoothSocket rfcSocket = mSPPCtrl.rfcConnect();
if (rfcSocket.isConnected()) {
mtvStatus.post(new Runnable() {
#Override
public void run() {
mtvStatus.setText("RFC-SOCKET CONNECTED");
}
});
} else {
mtvStatus.post(new Runnable() {
#Override
public void run() {
mtvStatus.setText("RFC-SOCKET NOT CONNECTED");
}
});
return;
}
// the rest of your logic
}
Some links that might help:
Android documentation on Threads
SO question Android basics: running code in the UI thread
another SO post on Update UI from Thread
The error here is really simple - do not use run() on the Thread instance, as this will actually run it's Runnable on the current Thread! Use start() and it will work fine :-)
I have a fragment that displays weather data that runs a background thread that essentially just calls a function in my main UI to check whether my forecast is still valid. This function updates the UI so I am using a Handler and posting a Runnable to the main thread, like so:
public class WaveFxListFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener {
// .....
// handler for dealing with synchronising update thread with UI
private Handler mHandler;
private UpdateThread mUpdateThread;
private class UpdateThread extends Thread {
volatile boolean running = false;
#Override
public void run() {
running = true;
while (running) {
// get main UI thread to perform update check:
Log.d(TAG, "Handler is " + mHandler);
mHandler.post(new Runnable() { // getting null pointer error here!
#Override
public void run() {
checkValidTime();
}
});
try {
Thread.sleep(1000); // sleep 1 second
} catch (InterruptedException e) {
Log.d(TAG, "Thread was interrupted!");
e.printStackTrace();
}
}
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Reuse existing handler:
mHandler = getActivity().getWindow().getDecorView().getHandler();
}
#Override
public void onResume() {
super.onResume();
// start update checker:
mUpdateThread = new UpdateThread();
mUpdateThread.start();
}
#Override
public void onPause() {
// stop update thread
Log.d(TAG, "Asking thread to stop");
mUpdateThread.running = false;
super.onPause();
}
}
This works fine; the problem is when I change my screen orientation. The current activity gets destroyed and if the thread is running, it tries to post a Runnable to a UI thread that no longer exists. So, I put a running member variable in the UpdateThread class and set if to false when my activity goes calls onPause. However, even though I have set the UpdateThread.running variable to false, my thread still tries to post a Runnable, but the Handler is now null! It shouldn't get that far, but it is!
Am I doing this wrong? My log message "Asking thread to stop" gets printed out, so I know it is getting as far as setting running to false.
Can anyone offer an insight?
Thanks
A few things that you can do to resolve this.
Interrupt the thread after you set running to false. This should cause the thread to exit earlier, or at the very least for your error to appear earlier.
Check that your handler is not null in your update thread, and set it to null in onPause.
Move the assignment of mHandler to onResume to make sure that mHandler is valid when the update thread is called.
At the moment I have the code from this site (link text) working great. In the example on the site it starts the recording for 10 seconds and then immediately plays the audio back in reverse. I have modified the code to start recording when a button is pressed, but can only get it to record for the 10 seconds and then save that file. I want to be able to start the recording by pressing a button and then stop the recording on a different button press. I have an idea that it could be an interrupt to the wait() method of the thread object but have no idea how to implement this. My code is as follows:
public void onClickRecord(View v){
text.setText("Recording");
Thread thread = new Thread(new Runnable() {
public void run() {
record();
}
});
thread.start();
synchronized(this) {
try {
wait(10000); //This is the 10 second waiting period while recording
}
catch (InterruptedException e) {
}
}
isRecording = false;
try {
thread.join();
} catch (InterruptedException e) {
}
}
public void onClickStop(View v){
//Here is what needs to be implemented to stop the recording.
}
There is quite a bit of code so I have only posted the bits I think are relevant. If any more is needed just ask.
Thanks.
try the AudioRecord Class !
I think that should be helpful.
Also look at AudioCapture here
http://developer.android.com/guide/topics/media/index.html