Multiple Handlers are conflicting with each other in Android - android

I'm trying to implement some type of function call in Handler in order to get function call multiple times. For this purpose I'm using Alarm Manager to start Handler. And I successfully did it.
The problem is that when AlarmManager repeats itself after a specific time a new Handle also be created again and the previous one was still here.
I want only one single handler which is being created and called no matter how many times AlarmManger repeat itself.
Here's my AlarmManger
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyBroadcastReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),1000*1, pi);
Here's my class where am I calling Handler
public class MyBroadcastReceiver extends BroadcastReceiver implements VolleyJsonRespondsListener {
final int delay = 10000; //milliseconds
final Handler handler = new Handler();
Runnable runnable;
#Override
public void onReceive(final Context context, Intent intent) {
Log.e("timeOut", "#"+CommonFunctions.getTime(System.currentTimeMillis()));
runnable=new Runnable() {
#Override
public void run() {
//do something
Log.e("timeInside", "#"+CommonFunctions.getTime(System.currentTimeMillis()));
handler.postDelayed(this, delay);
}
};
handler.postDelayed(runnable, delay);
}
In Logcat you can see that there are multiple handlers are conflicting their values with each other. I implemented system time in log and showing it in Logcat.
Locat

It's because during different instance creation of the Broadcast. It's handled by system with pending intent, so all you need it's just annotate Handler, as static object. This will ensure that only one handler created. Please note, this handler will bound to the main thread, because it will use current Looper.
static final Handler handler = new Handler();

you have to create thread and looper for that process see this code
public class MyBroadcastReceiver extends BroadcastReceiver {
final int delay = 10000;
final Handler handler = new Handler();
Runnable runnable;
#Override
public void onReceive(Context context, Intent intent) {
runnable=new Runnable() {
#Override
public void run() {
Looper.prepare();
handler.post(new Runnable() {
#Override
public void run() {
//do something
handler.postDelayed(this, delay);
}
});
Looper.loop();
}
};
}}

Related

Android: Start a thread in a service

i want to start a new thread in my own service which is started from an activity. In this thread I want to update data in a database after every 3 seconds. I created the databse and initializes it in my onStartCommand() method. Where should I implement my Thread and how?
I tried this but it didn't work, the app will be unfortunately closed. Without the call of this method everything works fin.
I create this method, which i called in my onStartCommand
private void startThreadUpdatingDatabase(){
Log.d("Database", "startThreadUpdatingDatabase(was called)");
new Thread(new Runnable() {
public void run(){
//do stuff
}
}).start();
}
If you want to start a recurring task you can try different approaches:
1) Alarm
2) Handler
3) TimerTask (My least favorite)
Alarm:
private AlarmManager mAlarmManager;
private static final long ALARM_INTERVAL = 3 * 60 * 1000;
private void issueAlarm() {
if(mAlarmManager == null)
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance(Locale.US);
calendar.add(Calendar.MILLISECOND, (int) ALARM_INTERVAL);
Intent intent = new Intent(this, AlarmBroadcastReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, ALARM_REQUEST_CODE, intent, 0);
mAlarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), ALARM_INTERVAL, alarmIntent);
}
Create your AlarmReceiver:
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Do DB Stuff here
}
}
And do not forget to register it in the manifest:
<receiver
android:name=".AlarmBroadcastReceiver"
android:exported="false" />
Handler:
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
And queue up your postedTask
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//As danny117 pointed out, multiple clients starting the service
//Can trigger this.
mServiceHandler.removeCallbacks(yourRunnable);
mServiceHandler.post(yourRunnable);
return super.onStartCommand(intent, flags, startId);
}
Runnable should look like:
private Runnable yourRunnable = new Runnable() {
#Override
public void run(){
//DB work here
if(mServiceHandler != null)
mServiceHandler.postDelayed(this, ALARM_INTERVAL);
}
}
Also clean up after service stops:
#Override
public void onDestroy() {
super.onDestroy();
mServiceHandler.removeCallbacks(yourRunnable);
mServiceLooper.quit();
}
Timer:
Create your Timer:
private Timer myTimer = new Timer();
Create the recurring Timer Task:
private void scheduleTask() {
myTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
//Do DB stuff here
}
}, 0, ALARM_INTERVAL);
}
References:
Scheduling Repeating Alarms
Creating a Service
To repeat with a delay you make a runnable that calls postDelayed of a handler to restart it after a set time period.
//change the notificationSmallIcon (titlebar) so it flashes every few seconds
private static Runnable iconWarnRunnable = new Runnable() {
#Override
public void run() {
if (isWarningRunning) {
long dely;
if (notificationSmallIcon == R.drawable.ic_launcher2) {
notificationSmallIcon = R.drawable.ic_launcher2x;
dely = iconWarnDelay1;
} else {
notificationSmallIcon = R.drawable.ic_launcher2;
dely = iconWarnDelay2;
}
notifyHandler.postDelayed(this, dely);
myShowNotification();
} else {
//just in nick of time
notificationSmallIcon = R.drawable.ic_launcher2;
}
}
};
final HandlerThread myThread = new HandlerThread("myHandlerThread");
private static long iconWarnDelay1;
private static long iconWarnDelay2;
#Override
public void onCreate() {
iconWarnDelay1 = 2500;
iconWarnDelay2 = 500;
myThread.start();
myThread.setPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
notifyHandler = new Handler(myThread.getLooper());
... somewhere you start the runnable it's really important that when you start you remove first so you always have just one running.
isWarningRunning = true;
notifyHandler.removeCallbacks(iconWarnRunnable);
notifyHandler.postDelayed(iconWarnRunnable, iconWarnDelay1);
... somewhere stop the runnable
isWarningRunning = false;
notifyHandler.removeCallbacks(iconWarnRunnable);

Stopping periodically running AsyncTask

See Update section below for my modified solution
Goal
To poll URL periodically (e.g. every 30 seconds), but only when activity is in foreground
Stop the polling if activity is not in foreground
Periodical execution
Handler object receiving Runnable object via the postDelayed method
In the run method of the Runnable object AsyncTask is started
In onPostExecute of the AsyncTask the postDelayed of the Handler object is called again
In onResume of the activity, post method of the Handler object is called
In onPause of the activity, removeCallbacks of the Handler object is called to remove pending posts of the Runnable in the message queue
Issue with cancelling of the polling
Even though I remove the pending posts of Runnable in onPause, it can still happen that the currently running AsyncTask that executes its doInBackground method adds new Runnable to the queue when its onPostExecuteis started (basically few moments later after the removeCallbacks was called in onPause)
How I solve it right now
boolean member variable shouldPoll was added to the activity
it is set to true in onResume, and to false in onPause
In onPostExecute of the AsyncTask I check if the shouldPoll is true and call the postDelayed of the Handler object only in that case
Concerns
Is using the shouldPoll variable OK?
I'm bit worried whether something can't happen to the activity (and thus the shouldPoll variable) in rare cases; therefore, somehow breaking the logic of the AsyncTask's onPostExecute
Source code snippets
MainActivity
boolean shouldPoll = false;
#Override
protected void onResume() {
super.onResume();
shouldPoll = true;
handler.post(pollURLRunnable);
}
#Override
protected void onPause() {
shouldPoll = false;
handler.removeCallbacks(pollURLRunnable);
super.onPause();
}
final Handler handler = new Handler();
final Runnable pollURLRunnable = new Runnable() {
public void run() {
PollingAsyncTask pollTimestampAsyncTask = new PollingAsyncTask();
pollTimestampAsyncTask.execute();
}
};
AsyncTask
#Override
protected void onPostExecute(Result result) {
if (result != null) {
//Do something here
}
if (shouldPoll) {
handler.postDelayed(pollURLRunnable, 10000);
}
}
Update
MainActivity
#Override
protected void onResume() {
super.onResume();
handler.post(startIntentServiceRunnable);
LocalBroadcastManager.getInstance(this).registerReceiver(statusBroadcastReceiver, new IntentFilter(Constants.MY_INTENT_FILTER));
}
#Override
protected void onPause() {
handler.removeCallbacks(startIntentServiceRunnable);
LocalBroadcastManager.getInstance(this).unregisterReceiver(statusBroadcastReceiver);
super.onPause();
}
final Handler handler = new Handler();
final Runnable startIntentServiceRunnable = new Runnable() {
public void run() {
Intent intent = new Intent(MainActivity.this, PollingService.class);
startService(intent);
}
};
final BroadcastReceiver statusBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
//...
//Do something useful with the extras from intent here
//...
handler.postDelayed(startIntentServiceRunnable, 2000);
}
};
PollingService
#Override
protected void onHandleIntent(Intent intent) {
//...
//Perform the polling and prepare results here
//...
broadcastResults();
}
private void broadcastResults() {
Intent intent = new Intent(Constants.MY_INTENT_FILTER);
//...
//Fill the intent extras with the data here
//...
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
You can skip the AsyncTask by making the hander run in a background thread. Then just move the work to the runnable you post to the handler.
HandlerThread handlerThread = new HandlerThread("Background thread");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());

How to start a service from Handler

I have a basic question on starting a Service.
I have a Service which starts a Thread for parsing a file; once this is done the same is communicated back by sending a Message.
Now, after receiving this Message in a Handler of the Service, I want to start another Service.
Since Handler doesn't have the Context, how do I start another Service?
One option is to send a local broadcast and receive the same and start Service, but is there any other way of doing it?
Just make a custom handler who need a Context :
public class CustomHandler extends Handler {
Context mContext;
public CustomHandler(Context context) {
mContext = context;
}
public void handleMessage(Message msg) {
if(msg.what == ID_STARTSERVICE) {
Intent i = new Intent...
mContext.startService(i);
}
}
}
But make sure you pass the ApplicationContext ( new CustomHandler(getApplicationContext() ) ) and not an Activity context.
It'll be something like this
public int onStartCommand(Intent intent, int flags, int startId)
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.mainActivity);
Message msg = new Message();
msg.what = 0;
mHandler.sendMessage(msg);
}
Handler mHandler = new Handler()
{
public void handleMessage(android.os.Message msg) {
if(msg.what==0)
{
StartService(new Intent(Myservice.this, secondservice.class));
finish();
}
};
};
You can start service from Handler without using reference to Context this way:
Intent serviceIntent = new Intent();
serviceIntent.setAction("your.package.UpdaterServieName");
startService(serviceIntent);
I hope I understood your question and this reply could be useful to you.
Sorry for my english.

Only one instance of Thread in service

I initialize new Thread in service but when i start service the new one is made and it make my app crash beacause I use camera in it.
How to make that it will be ony one instance of that Thread?
When Thread is closing? If I close service where I made it, it will be also closed?
you could use a lock or a static variable:
private static boolean isThreadRunning;
and then in your service:
if(isThreadRunning)
return;
Thread t=new Thread(new Runnable(){
protected void run(){
isThreadRunning=true;
while(yourcondition){
//your thread code...
}
isThreadRunning=false;
//if you want to start another thread after this one is ended, you should post a message to a handler here and it should start another thread like this
}
});
You can also achieve this using Handler class, which is recommended by Google in thread operations. The code bellow shows generic example how to use it in Service.
public class MyService extends Service{
private final Handler handler = new Handler();
private final static int RUNABLE_WHAT=6558057;
private final static int PEROID=6*1000;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(!handler.hasMessages(RUNABLE_WHAT))
{
handler.sendMessageDelayed(new Worker().extractMessage(), PEROID);
}
return START_STICKY;
}
private class Worker implements Runnable{
#Override
public void run() {
//DO WORK HERE
handler.sendMessageDelayed(new Worker().extractMessage(), PEROID);
}
private Message extractMessage()
{
Message message = Message.obtain(handler, this);
message.what=RUNABLE_WHAT;
return message;
}
}
}

service freezes the activity?

I have a service that gets the location and sends it to a server, also I have an activity that starts and stops the service with a button. When I start up the service all the buttons do not work and after a while the activity force closes giving the option to wait or close. what could be causing the problem?
I did something like that before ... I dont post the whole code, jsut the main thing. This wont run, i just want to give you the idea, of what to llok for and how to handle it.
The magic is done in sendUpdatesToUI... I saved myself all the unimportant methods that are overwritten when you implement LocationListener - you know best, which of them you need.
class:
public class ServiceLocator extends Service implements LocationListener
public static final String BROADCAST_ACTION = "my.app.isgreat";
private final Handler handler = new Handler();
private LocationManager locationManager;
Intent intent;
public void onCreate() {
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
intent = new Intent(BROADCAST_ACTION);
}
public void onStart(Intent intent, int startId) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, DEBUG_DELAY);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
DEBUG_DELAY, 3, this);
}
#Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(sendUpdatesToUI);
locationManager.removeUpdates(this);
locationManager = null;
}
//Here is the second thread, that won'z freeze your UI
//DisplayLogginInfo() sets all the values you wanna send
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
DisplayLoggingInfo();
handler.postDelayed(this, DEBUG_DELAY);
}
};
private void DisplayLoggingInfo() {
intent.putExtra("long", String.format("%.4f", lastLocation.getLongitude()));
sendBroadcast(intent);
}
It probably won't run that way, because I kicked out all the uninteresting stuff, but it should give you an idea, how to programm a locationthread, which won't freeze your UI.
Have fun

Categories

Resources