How to handle button click while using AsyncTask? - android

I am developing alarm app.
I used broadcast receiver to receive alarm time.
When alarm times up, I show a activity which starts ringtone & vibrate using AsyncTask for 2 minutes.
In this activity I have two buttons named
Plus
Minus
When I press any of these buttons its click event is delaying to fire, means not getting clicked as I press button due to asyncTask running in backgroung(playing ringtone).
I read that asyncTask runs on seperate thread,
Than my button click event should fire as it pressed but in this case its not doing same.If any body had this situation and got solution then please suggest me!
Below is my code.
called using :
new RingtonePlay ().execute("");
following is implementation.
public class RingtonePlay extends AsyncTask<String,Void, String>
{
#Override
protected void onPreExecute()
{
super.onPreExecute();
try
{
audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
originalVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
vibratorObj = (Vibrator)mContext.getSystemService(Context.VIBRATOR_SERVICE);
volume = originalVolume;
listObjs.clear();
listObjs.add(audioManager);
listObjs.add(originalVolume);
listObjs.add(vibratorObj);
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Override
protected String doInBackground(String... params)
{
try
{
Cursor cursorSettings = dbHelper.getAllRecords(Info.SETTINGS);
if(cursorSettings!=null && cursorSettings.getCount()>0)
{
cursorSettings.moveToFirst();
durationInMilliSeconds = cursorSettings.getString(cursorSettings.getColumnIndex(Info.DEFAULT_DURATION));
vibrate = cursorSettings.getInt(cursorSettings.getColumnIndex(Info.DEFAULT_VIBRATE));
if(toneName.equals(""))
{
toneName = cursorSettings.getString(cursorSettings.getColumnIndex(Info.DEFAULT_TONE_NAME));
tonePath = cursorSettings.getString(cursorSettings.getColumnIndex(Info.DEFAULT_TONE_PATH));
}
listObjs.add(vibrate); // For vibration [ YES = 1, NO = 0]
}
else
{
listObjs.add(0); // For vibration [ YES = 1, NO = 0]
}
if(cursorSettings!=null)
cursorSettings.close();
durationInMilliSeconds = 5000;
ringTone = RingtoneManager.getRingtone(mContext, tonePathURI);
if(ringTone!=null)
{
ringTone.play();
}
if(ringTone==null && vibrate==0)
{
// No need to start any counter...
}
else
{
timer = new MyCountDownTimer(durationInMilliSeconds, 1000, ringTone, mContext, listObjs);
timer.start();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return "";
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
}
}

Of the 4 functions in AsyncTask, only doInBackground() is running in its own Thread off of the main UI Thread. Therefore, make sure that you are playing your ringtone from within doInBackground() and that you are starting the AsyncTask with its execute() function.
AsyncTask.doInBackground() will not stop your Button presses from firing unless you have called it directly instead of executing the AsyncTask.
Presumably, you have a short sound file which you are playing over and over for 2 minutes.
Each time the sound finishes playing, you should check for several things to decide if you should play again. A while() loop within doInBackground() will work well for this.
If two minutes have elapsed, don't play the sound again.
Your "Plus" and "Minus" Button presses can modify the two minute time.
You can add a "Stop" button to zero out the time and stop the
AsyncTask at the next cycle.

Related

Timer not working in app

I have written schedule task by using timer. It is working fine withing single activity.But when i am going to another activity it is not working.My intention is to send data to the server some particular time interval. I am giving the code snippet. I am sorry for the format.
private void login()
{
try {
EditText userNameET = (EditText)findViewById(R.id.userName);
EditText passwordET = (EditText)findViewById(R.id.password);
String userName = userNameET.getText().toString();
String password = passwordET.getText().toString();
boolean isLoginOK = isValidUser(userName, password);
String autoSynchStrVal = "";
String autoSyncFreqStr = "";
long autoSyncFreqInMiliSec = 3600000; // default 1 hrs
if (isLoginOK) {
//added by anirban
CommonUtils.IS_NEW_VERSION_AVAILABLE = isNewVersionAvailable();
CommonUtils.IS_NEW_Notification_AVAILABLE = isNewNotificationAvailable();
autoSynchStrVal = CommonUtils.getPolicyValue(appInstance, "IS_MOBI_AUTO_SYNCH_REQ", 0, 0);
if(autoSynchStrVal != null && !"".equals(autoSynchStrVal) && "1".equals(autoSynchStrVal)){
//boolean isAllTransactionsUploaded = false;
// boolean isAllTransactionsUploaded = VersionCheckingActivity.isAllTransactionsUploaded();
// boolean isMobiEligibleForAutoSync = UploadDownload.isMobiEligibleForAutoSync(appInstance ,isAllTransactionsUploaded);
// if(isMobiEligibleForAutoSync){
autoSyncFreqStr = CommonUtils.getPolicyValue(appInstance, "MOBI_AUTO_SYNCH_FREQUENCY", 0, 0);
if(autoSyncFreqStr != null && !"".equals(autoSyncFreqStr)){
autoSyncFreqInMiliSec = (long) (Double.valueOf(autoSyncFreqStr) * 60 * 60 * 1000); // in millisecond
}
/* boolean isMobiEligibleForAutoSync = false;
try {
isMobiEligibleForAutoSync = UploadDownload.isMobiEligibleForAutoSync(appInstance ,
VersionCheckingActivity.isAllTransactionsUploaded());
if(isMobiEligibleForAutoSync){
_doSynch();
}
} catch (UDBAccessException e) {
e.printStackTrace();
} */
myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
ULoginActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// here we are checking again for eligibility for auto synch
boolean isMobiEligibleForAutoSync = false;
try {
isMobiEligibleForAutoSync = UploadDownload.isMobiEligibleForAutoSync(appInstance ,
VersionCheckingActivity.isAllTransactionsUploaded());
Log.d("inside Run : ", "before Synch");
if(isMobiEligibleForAutoSync){
_doSynch();
Log.d("inside Run : ", "after Synch");
}
} catch (UDBAccessException e) {
e.printStackTrace();
}
}
});
}
}, 1000, autoSyncFreqInMiliSec); //here interval is autoSyncFreqInMiliSec
}
endAction(RESULT_LOGIN_OK, null); // it will finish the activity
} else {
// showing login error
TextView login_msg = (TextView)findViewById(R.id.login_screen_msg);
login_msg.setTextAppearance(this, R.style.error_msg);
//login_msg.setTextColor(Color.RED);
login_msg.setText("Login failed.");
}
} catch (UDBAccessException e) {
UUIHandlers.showErrorMessage(this, e.getMessage());
}catch (Exception e) {
UUIHandlers.showErrorMessage(this, e.getMessage());
}
}
To make it work when you leave the current activity, you have to run that code of snippet on the background service.
As you are executing on the current Activity it runs the code for the first time, but as you leave the activity the code wont be triggered itself unless it is registered to a background service.
Here and here you have examples on how to use them
If you want to execute something after some time, even when your activity is not currently in the foreground, you can use the AlarmManager.
Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
If you want to periodically send information to a server, I suggest you use a Service or an IntentService.
A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.
You can find a good example using a LocalService also here.
Finally got the solution .
Now from Async task( different thread), You are trying to insert data in the database which is locked by UI thread. This will throw an exception because the first write has a lock on the db.
If you hold your timer in a field of your activity (Activity subclass) it will probably go away once you launch another activity. Consider moving your timer to service (Service subclass). This will hold your timer going regardless of your activity flow.
Read this for reference about services:
https://developer.android.com/guide/components/services.html

how to stop a running thread with button toggle (android app)

I finally got my app working, i just have one issue which i would like to correct.
I have a button which controls a thread that runs a couple function in the background. The functions in the background eventually stop the thread whenever a certain value is reached. What i am having issues doing is pressing that same button again to just stop the thread manually. Currently I can only start the thread and wait for itself to finish. I am able to do other things in the app, so the thread is running on its own, i just want to kill it manually.
public void onMonitorClick(final View view){
if (isBLEEnabled()) {
if (!isDeviceConnected()) {
// do nothing
} else if (monitorvis == 0) {
showMonitor();
DebugLogger.v(TAG, "show monitor");
//monitorStop = 4;
Kill.runThread(); // I want a function here that would kill the
// thread below, or is there something that
// can be modified in runThread()?
// I did try Thread.Iteruppted() without luck
shutdownExecutor();
} else if (monitorvis == 1) {
hideMonitor();
DebugLogger.v(TAG, "hide monitor");
monitorStop = 0;
runThread(); //The running thread that works great on its own
}
}
else {
showBLEDialog();
}
}
private void runThread() {
new Thread() {
int i;
public void run() {
while (monitorStop != 3) { //This is where the thread stops itself
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
((ProximityService.ProximityBinder) getService()).getRssi();
rssilevel = ((ProximityService.ProximityBinder) getService()).getRssiValue();
mRSSI.setText(String.valueOf(rssilevel) + "dB");
detectRange(rssilevel);
}
});
Thread.sleep(750);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
On first look, you could simply set monitorStop = 3, which would cause the thread to eventually stop after it's timeout completes.
The problem with this, is that I presume if you push the button again or your code modifies monitorStop at some point in the future, then the thead you wanted dead, might stay alive. ie: monitorStop will need to stay equal to three for at least 750ms to assure the thread will comlete it's loop and die.
The correct way to do this would be to create your thread as a new class with it's own monitorStop parameter. When you create the thread, you would keep a reference to it and modify the thread's monitorStop parameter. This way the thread would finish without interruption. If you wanted to create a new thread, then this would not affect the old thread from finishing appropriately.

Activity A starts Activity B, how to close Activity A

I seem to be here quite a bit!!
I know this question has been asked already on here and in other places and I have tried to implement answers posted but it's not working for me
I have an activity, (Activity A) based on an if statement, it starts Activity B. My problem is Activity A keeps running, and in Activity A I play an alarm and vibrate the phone, both keep going and while Activity B starts and runs (I can see in the logcat) it never comes to the front because of that.
Here is my code of my if statement
if (dynamicActivation > threshold) {
alarmHandler.post(new Runnable() {
public void run() {
int duration = Toast.LENGTH_SHORT;
CharSequence text = "YOUR CHILD HAS TRAVELLED OUTSIDE PROXIMITY";
Context context = getApplicationContext();
proximityAlert = Toast.makeText(context, text,
duration);
proximityAlert.show();
alarmSound.start();
//v.vibrate(3000);
try {
Thread.sleep(5000);
openMaps();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
And here is the code from the openMaps() function
public void openMaps() {
Class track = ParentReal.class;
Intent PRealIntent = new Intent(this, track);
PRealIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(PRealIntent);
ANN.this.finish();
}
I should add in case it causes problems is that there is another activity, a menu, once a button is clicked it opens Activity A...should I be closing the menu activity as well once I start Activity A?
Thanks in advance!
EDIT
I'm not to sure why the downvote, but I'll try and explain my problem, I have three activities A, B, C. A is my menu, upon button click it starts Activity B, in activity B, based on the outcome of an if statement Activity C is started.
The problem is C runs, the processes can be see in the logcat but doesn't open. B continues to play the alarm and vibrate and then the phone stalls and the alarm and vibrate continue. I have the code for the if statement above and the code for the openMaps() function as well, this is called based on the outcome of the if, in which I try to open Activity C and close B
I hope that is clearer ;)
ANOTHER EDIT
ok, I have an idea what the problem is, I just don't know how to solve it. I have a thread, inside that thread is an infinate while loop, inside this infinite while loop I check the distance between two coordinates (i want them constantly updating).
The problem is, variables I have declared globally are initialized within the loop so I have to run my if statement within that, to access those...I tried using a boolean 'test' that if it's true execute the if statement then set test to false but that doesn't work I'm afraid.
here's my code
Thread dist = new Thread(new Runnable() {
public void run() {
while (true) {
child = new Location("point A");
child.setLatitude(Clatitude);
child.setLongitude(Clongitude);
parent = new Location("point B");
parent.setLatitude(Platitude);
parent.setLongitude(Plongitude);
distance = child.distanceTo(parent);
DisRound = 550;
dynamicActivation = DisRound * weight;
try {
Thread.sleep(1000);
if (test)
{
if(dynamicActivation > threshold)
{
finish();
new Timer().schedule(new MapsTimer(), 5000);
test = false;
}
Log.d("ACTIVATION", Boolean.toString(test));
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
dist.start();
and heres the MapsTimer task
private class MapsTimer extends TimerTask {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
int duration = Toast.LENGTH_SHORT;
CharSequence text = "YOUR CHILD HAS TRAVELLED OUTSIDE PROXIMITY";
Context context = getApplicationContext();
proximityAlert = Toast.makeText(context, text, duration);
proximityAlert.show();
alarmSound.start();
openMaps();
}
});
}
}
I am calling finish within the if statement. I've been at this for 10 hrs now and it's melting my head, I'm sure it's simple, but only when you know how!!
Regards,
Gary
Your question and your code are not clear, but in general after the code which switch you to activity B you should call finish() which finish activity A
Thank you everyone for all your help, I sorted it myself. I just inserted a break in the while loop. As follows:
Thread dist = new Thread(new Runnable() {
public void run() {
while (true) {
child = new Location("point A");
child.setLatitude(Clatitude);
child.setLongitude(Clongitude);
parent = new Location("point B");
parent.setLatitude(Platitude);
parent.setLongitude(Plongitude);
distance = child.distanceTo(parent);
// DisRound = Math.round(distance * 100.0) / 100.0;
DisRound = 550;
dynamicActivation = DisRound * weight;
try {
Thread.sleep(1000);
if(dynamicActivation > threshold)
{
proximityAlert.show();
alarmSound.start();
new Timer().schedule(new MapsTimer(), 5000);
break;
}
Log.d("ACTIVATION", Boolean.toString(test));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
finish();
}
});
dist.start();
So once the alert is shown, the alarm is played, and the mapsTimer is called, it breaks out of the infinite loop, it isn't needed any more and then I call finish();

Making a Simple Recurring Text Update Continue Indefinitely

I have a very function function inside the activity that takes a static date in the past, formats it to a relative string using DateUtils.getRelativeDateTimeString (so it becomes something like "3 minutes ago" and sets it to a TextView. However, I want this TextView to keep updated so long as the activity stays open.
How do I make a continuous task that will either run continuously (infinite loop) or run within short intervals - like every second. How to accomplish this without getting into background services and such?
Here is an example using AsyncTask
private class BackgroundCoversionTask extends AsyncTask< String, String, Void >{
#Override
protected Void doInBackground( String... params ) {
while( !isCancelled() ){
try {
Thread.sleep( 1000 );
} catch ( InterruptedException e ) {
break;
}
//DateUtils.getRelativeDateTimeString( MainActivity.this, time, minResolution, transitionResolution, flags )
// Do something right here
publishProgress( Long.toString( System.currentTimeMillis() ) );
}
return null;
}
#Override
protected void onProgressUpdate( String... values ) {
super.onProgressUpdate( values );
mTextView.setText( values[0] );
}
}
Then if you want to cancel the task, call cancel()
Just run it on a separate thread.
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
//Do your date update here
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
See: How to run a Runnable thread in Android?
With threads please make sure that when the app is paused or resumed you appropriately pause or resume your thread. Also it is a good idea to end them yourself at the end of the activity lifecycle for the sake of handling any data you might want

Make activity wait for specific time period

I have following code snippet in my application activity.
If user is landing on activity for the first time then only thing that will happen is changing the boolean variable shouldSleep to true.
Thereafter, else part will be executed which contains generation of notification at every 60 seconds.
But the main problem is if I execute this code, the activity NEVER gets displayed as it keeps looping in else part and hence go on sleeping.
What I want is remaining application should run normally while every 60 seconds, else part of this method should be executed.I guess it has got something to do with AsyncTask but I don't have much idea about it.
Any idea how to do this? Thanks in advance for your help.
boolean shouldSleep=false;
private void ShowNotification()
{
//DO SOME TASK
if (shouldSleep)
{
Thread.sleep(60000);
//DO SOME TASK
}
else
{
shouldSleep = true;
}
/** Calling the method recursively so that it always runs. */
ShowNotification();
}
Maybe you can use a Timer object :
new Timer().schedule(new TimerTask() {
#Override
public void run() {
//This code is run all 60seconds
myBooleanVar = true;
//If you want to operate UI modifications, you must run ui stuff on UiThread.
Activity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Activity.this.changeUiStuff();
}
});
}
}, 60000);
Just use a Timer. Instead of a thread approach, you could run your task every 60s:
new Timer().schedule(task, delay, period);
with period = 60*1000

Categories

Resources