Services - Broadcasting between activity and service - android

I know there are many threads on Stackoverflow on this topic, and I have read each and every single one, but I am still very confused and am very sorry but I feel like I should post this.
When the application is run nothing really happens with the receivers, as if they are not receiving anything
My service:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int timerValue = pv.getTimerValues();
aCounter = new CountDownTimer((timerValue), 1000) { // set to
// timerValue
// later
public void onTick(long millisUntilFinished) {
int minutes, seconds;
String sSeconds, sMinutes, toSend;
seconds = (int) (millisUntilFinished / 1000) % 60;
minutes = (int) ((millisUntilFinished / (1000 * 60)) % 60);
sSeconds = Integer.toString(seconds);
sMinutes = Integer.toString(minutes);
toSend = (sMinutes + ":" + sSeconds);
sendMessage(toSend);
countDownCheck();
}
public void onFinish() {
MediaPlayer dingeffect = MediaPlayer.create(
getApplicationContext(), R.raw.timerfinished);
// mPlayer0.stop();
try {
dingeffect.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dingeffect.start();
// Intent intent2 = new Intent(ServiceTest.this, Meditate.class);
//startActivity(intent2);
sendMessage("finished");
}
};
aCounter.start();
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
private void sendMessage(String send) {
Intent intent1 = new Intent("countdowntimer");
// You can also include some extra data.
intent1.putExtra("message1", send);
sendBroadcast(intent1);
}
My receiving activity:
Inside the onCreate:
registerReceiver(mMessageReceiver1, new IntentFilter("countdowntimer"));
final Intent countDownService = new Intent(Meditate2.this,
ServiceTest.class);
startService(countDownService);
and my broadcastreceiver inside the same activity
private BroadcastReceiver mMessageReceiver1 = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message1");
setTimer(message);
}
};
In the manifest I have declared the service as such:
<service android:name=".ServiceTest"></service>
The weird thing is, it was working then after I fixed some other stuff this stopped working, so I really have no clue why it is not. Help please!

I will tell you what is different between your code and my (working) code.
In the activity onCreate:
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver1, new IntentFilter("countdowntimer"));
In the activity onDestroy:
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver1);
In sendMessage:
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
I don't know if this makes a lot of difference, but I used LocalBroadcastManager.getInstance.

Your broadcast receiver should know what intents to listen to.
Register your receiver with an intentFilter that listens to your countdowntimer intent like this:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("countdowntimer");
activity.registerReceiver(this, intentFilter);

Related

Updating UI from Service in Android

I have an App that Monitors room noise levels, I initially got the Code from Github, in the original code, the programmer was monitoring noise levels from Main Activity and displaying the results in textviews, but I want to monitor using a service, I have implemented everything and its working but the textviews seem to be lagging behind, lets say I make a bit of noise and the noise level reach 5, it sticks at 5 even when there is no noise in the room, but in the original app, it was so sensitive that it would go back to 0 or another value depending on the noise levels, I do not know where I have gone wrong but below is my code:
Main Activity
public class StartingPoint extends Activity {
private String volumeBars;
private String volumeLevel;
private TextView volumeBarView;
private TextView volumeLevelView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(getBaseContext(), "Loading...", Toast.LENGTH_LONG).show();
setContentView(R.layout.activity_starting_point);
//starting Service
startService(new Intent(this, VolumeListerner.class));
volumeBarView = (TextView) findViewById(R.id.volumeBars);
volumeLevelView = (TextView) findViewById(R.id.volumeLevel);
}
#Override
public void onResume() {
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter("UI_UPDATER"));
super.onResume();
// Sound based code
}
#Override
public void onPause() {
super.onPause();
}
public void updateTextView() {
volumeBarView.setText(volumeBars);
volumeLevelView.setText(volumeLevel);
return;
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
volumeBars = intent.getStringExtra("VolumeBars");
volumeLevel = intent.getStringExtra("volumeLevel");
Log.d("receiver", "Got message: " + volumeBars + " : " + volumeLevel);
updateTextView();
}
};
Service:
public class VolumeListerner extends Service {
private static String volumeVisual = "";
private static int volumeToSend;
private Handler handler;
private SoundMeter mSensor;
/** interface for clients that bind */
IBinder mBinder;
/** indicates whether onRebind should be used */
boolean mAllowRebind;
/** The service is starting, due to a call to startService() */
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
soundLevelCheck();
return super.onStartCommand(intent, flags, startId);
}
private void soundLevelCheck()
{
mSensor = new SoundMeter();
try {
mSensor.start();
Toast.makeText(getBaseContext(), "Sound sensor initiated.", Toast.LENGTH_SHORT).show();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
// Get the volume from 0 to 255 in 'int'
double volume = 10 * mSensor.getTheAmplitude() / 32768;
volumeToSend = (int) volume;
volumeVisual = "";
for( int i=0; i<volumeToSend; i++){
volumeVisual += "|";
updateUI();
}
handler.postDelayed(this, 250); // amount of delay between every cycle of volume level detection + sending the data out
}
};
// Is this line necessary? --- YES IT IS, or else the loop never runs
// this tells Java to run "r"
handler.postDelayed(r, 250);
}
private void updateUI()
{
Intent intent = new Intent( "UI_UPDATER" );
intent.putExtra("VolumeBars", "Volume Bars: " + String.valueOf(volumeVisual));
intent.putExtra("volumeLevel","Volume Levels: " + String.valueOf(volumeToSend));
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
I recommmand you to use an enhanced event bus with emphasis on Android support. you have a choice between :
1- Otto
2- Event Bus

How can I control some web API per x minutes on service?

I want to check some web API and do something per x minutes. I think I should write a service on Android (is there any other solution?).
But how can do that?
I am thinking about writing a service class and in the manifest file I should add this line:
<service
android:name="com.xx.yy.noti_check"
android:enabled="true"
>
</service>
And in my noti_check class I check my web API like this on onStartCommand:
public class noti_check extends Service {
Context mcont;
private Handler myhandler ;
private long RETRY_TIME = 15000;
private long START_TIME = 2000;
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onStart(Intent intent, int startId) {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mcont=this;
myhandler= new Handler();
myhandler.postDelayed(myRunnable, START_TIME);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
try {
myhandler.removeCallbacks(myRunnable);
}
catch (Exception e) {
// TODO: handle exception
}
}
private Runnable myRunnable = new Runnable() {
public void run() {
try {
new get_notifyalert(mcont).execute("") ;
}
catch (Exception e) {
// TODO: handle exception
}
myhandler.postDelayed(myRunnable, RETRY_TIME);
}
};
}
Is this is the right way?
Is this the right way?
No. Only have a service running when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user. Use AlarmManager for periodic work like this.

Service that runs every minute

I have a service that I am wanting to execute a task every minute in the background. It does not need to execute the task whenever the phone is asleep, only when the user is actively using it. I am trying to do this with an IntentService which is set up as follows:
public class CounterService extends IntentService{
public CounterService() {
super("CounterService");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent,flags,startId);
}
#Override
protected void onHandleIntent(Intent intent) {
Toast.makeText(this, "onhandleintent", Toast.LENGTH_SHORT).show();
while(true)
{
//one minute is 60*1000
try {
Thread.sleep(5 * 1000);
Toast.makeText(getApplicationContext(), "getting app count", Toast.LENGTH_LONG).show();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Right now to get the functionality working I simply want it to display a toast every 5 seconds, I will change it to one minute later. If I have the while(true) commented out, then the "onhandleintent" message is displayed. However if I have the following code run, neither of the Toasts display. How can I fix this?
This will send an intent to your service every minute without using any processor time in your activity in between
Intent myIntent = new Intent(context, MyServiceReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 60); // first time
long frequency= 60 * 1000; // in ms
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), frequency, pendingIntent);
Adjust MyServiceReceiver.class to match your target service or activity.
The documentation provides more details to fine-tune your calls like whether you want exact timing, execution at a specific time of the day ...
You need to exit the main thread to avoid risking a ANR.
Instead add a Handler
Handler mHandler = new Handler();
...
#Override
protected void onHandleIntent(Intent intent) {
Toast.makeText(this, "onhandleintent", Toast.LENGTH_SHORT).show();
mHandler.postDelayed( ToastRunnable, 5000);
//while(true)
//{
//one minute is 60*1000
//try {
// Thread.sleep(5 * 1000);
// Toast.makeText(getApplicationContext(), "getting app count",
//Toast.LENGTH_LONG).show();
//} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
//}
//}
}
final Runnable ToastRunnable = new Runnable(){
public void run(){
Toast.makeText(getApplicationContext(), "getting app count",
Toast.LENGTH_LONG).show();
mHandler.postDelayed( ToastRunnable, 5000);
}
}
Do it like this
private void ping() {
try {
//Your code here or call a method
} catch (Exception e) {
Log.e("Error", "In onStartCommand");
e.printStackTrace();
}
scheduleNext();
}
private void scheduleNext() {
mHandler.postDelayed(new Runnable() {
public void run() { ping(); }
}, 60000);
}
public int onStartCommand(Intent intent, int x, int y) {
mHandler = new android.os.Handler();
ping();
return START_STICKY;
}

Why didn't accelerometer start on time or retrieve data normally?

I write an app that schedule to start accelerometer every 15 seconds and run it 10 seconds to retrieve sensor data. I start accelerometer using alarmManager and keep it running with wakelock when screen go off. But I found sometimes:
The accelerometer can't retrieve data after some periods. I mean it have been started according to logcat,but there is not any sensor data,then it is closed and it starts again without data.
I don't know why the accelerometer didn't start any more after some periods and it is fine before. I found logcat says "listener with binder android.os.BinderProxy doesn't exist accelerometer". I don't know why.
following is kernel code:
Activity.java
Intent intent = new Intent(getApplicationContext(),SensorService.class);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long curTime = Calendar.getInstance().getTimeInMillis();
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, curTime, _intervalTime, pendingIntent);
SensorService.java
public void onStart(Intent intent, int startId) {
new Thread(new Runnable(){
public void run() {
// TODO Auto-generated method stub
wl.acquire();
Log.d(TAG,"I'm bright!");
try {
Thread.sleep(_delayClose);// kill self after _delayClose ms
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
stopSelf();// SensorService.this.stopSelf()
}
}).start();
this.mSensorManager.registerListener( _sensorHandle,
accSensor,
sensorDelay)
}
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
this.mSensorManager.unregisterListener(_sensorHandle);
Log.d(TAG,"TIEM UP");
if(wl.isHeld())
{
wl.release();
}
}
I'm guessing that there must be some considerable overhead in registering and unregistering sensor listener that often, plus the alarmManager overhead.
Given that you want sensor data that often, how about just keep your listener registered and have it internally manage when it should and shouldnt do something useful with the samples it's receiving?
public class SensorSamplrActivity extends Activity {
private final static String TAG = "samplr";
private final static int SAMPLE_INTERVAL_SECS = 15;
private final static int SAMPLE_DURATION_SECS = 10;
private SensorManager mSensorManager;
private long whenToStartSample = System.currentTimeMillis();
private long whenToEndSample = System.currentTimeMillis() + SAMPLE_DURATION_SECS;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_GAME);
}
private SensorEventListener mSensorListener = new SensorEventListener() {
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
long now = System.currentTimeMillis();
if (now < whenToStartSample){
// ignore the event & wait for next time to sample
Log.d(TAG,"ignoring events for " + (whenToStartSample - now) + "ms");
return;
}
if (whenToStartSample <= now && whenToEndSample > now){
Log.d(TAG,"Do something with this event # " + now);
}
else {
// we've gone past whenToEndSample so reset timers
whenToStartSample = now + (SAMPLE_INTERVAL_SECS * 1000);
whenToEndSample = whenToStartSample + (SAMPLE_DURATION_SECS * 1000) ;
}
}
};
#Override
public void onDestroy(){
super.onDestroy();
mSensorManager.unregisterListener(mSensorListener);
}
}

Error Thread already started / scheduled

Friends,
I set up an AlarmManager within my application. The AlarmManager is scheduled to start a background Service every xx , here 1 Min. Its working quite well for a while. But freuqently I get an Error: thead already started / scheduled.
I have the feeling that i might dont use destructors correct.
Would be grateful for your support.
Heres my code of the Activity that starts the AlarmManager
PendingIntent pi;
AlarmManager mgr;
mgr=(AlarmManager)ctx.getSystemService(Context.ALARM_SERVICE);
Intent i=new Intent(DataCollectionActivity.this, HUJIDataCollectionService.class);
pi = PendingIntent.getService(DataCollectionActivity.this, 0, i, 0);
........
if (viewId == R.id.b_startService) {
mgr.cancel(pi);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() , 1* 60* 1000, pi);}
........
if (viewId == R.id.b_stopService) {
mgr.cancel(pi);}
and heres the important code of my Service:
private Runnable LocationUpdateTimerTask = new Runnable() {
public void run() {
Log.i(ctx.getString(R.string.app_name),
"HUJIDataCollectionService, 1 LocationUpdateTimerTask, start");
setuplistenerandrequestupdates();
mHandler.removeCallbacks(LocationUpdateTimerTask);
}
};
private Runnable SendDataStopLocationUpdatesTimerTask = new Runnable() {
public void run() {
sendDataToServer();
mHandler.removeCallbacks(SendDataStopLocationUpdatesTimerTask);
ServiceIntervalTimerTask.cancel();
Intent service = new Intent(ctx, HUJIDataCollectionService.class);
stopService(service);
}
};
private TimerTask ServiceIntervalTimerTask = new TimerTask() {
#Override
public void run() {
// remove old timer updates
mHandler.removeCallbacks(LocationUpdateTimerTask);
mHandler.removeCallbacks(SendDataStopLocationUpdatesTimerTask);
// Start TimerTasks delayed
mHandler.postDelayed(LocationUpdateTimerTask, 1000);
mHandler.postDelayed(SendDataStopLocationUpdatesTimerTask,
conf_LocationUpdatePeriodInSec * 1000);
}
};
#Override
public void onDestroy() {
super.onDestroy();
startDataCollectionServiceIntervallTimer.cancel();
startDataCollectionServiceIntervallTimer = null;
// Remove all kinds of updates
mHandler.removeCallbacks(LocationUpdateTimerTask);
mHandler.removeCallbacks(SendDataStopLocationUpdatesTimerTask);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startDataCollectionServiceIntervallTimer = new Timer(
"HUJIDataCollectionServiceStartTimer");
startDataCollectionServiceIntervallTimer.schedule(ServiceIntervalTimerTask,
1000L, conf_sampleTimeInMin * 60 * 1000L);
mHandler = new Handler();
return START_STICKY;
}
When you start a service it runs in the backround even when app is destroyed. Where and when you call your Alarm manager??? But if you often call a service i think that you will have memory leak or something like that...
I think i found the solution for the problem my own.
First i bypassed the problem by starting a Broadcastreceiver. But this is not an answer to the described problem.
Here is a solution:
public void pause(){
while(true){
try { // goes through this thread until our thread died
ourthread.join(); //Blocks the current Thread (Thread.currentThread()) until the receiver finishes its execution and dies.
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
Thanks for the support anyways!!!
Cheers

Categories

Resources