Service containing BroadCastReceiver not functioning correctly - java

Please see edits before answering!
I have an app which contains a BackgroundService class:
public class BackgroundService extends Service {
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction("com.spotify.music.playbackstatechanged");
filter.addAction("com.spotify.music.metadatachanged");
filter.addAction("com.spotify.music.queuechanged");
registerReceiver(receiver, filter);
Log.e("Playing:", "APP IS PLAYING");
Notification notification = new Notification();
startForeground(1, notification);
}
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
long timeSentInMs = intent.getLongExtra("timeSent", 0L);
String action = intent.getAction();
if (action.equals(BroadcastTypes.METADATA_CHANGED)) {
String trackId = intent.getStringExtra("id");
String artistName = intent.getStringExtra("artist");
String albumName = intent.getStringExtra("album");
String trackName = intent.getStringExtra("track");
int trackLengthInSec = intent.getIntExtra("length", 0);
// Do something with extracted information...
} else if (action.equals(BroadcastTypes.PLAYBACK_STATE_CHANGED)) {
boolean playing = intent.getBooleanExtra("playing", false);
Log.e("Playing:","TRUE");
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
static final class BroadcastTypes {
static final String SPOTIFY_PACKAGE = "com.spotify.music";
static final String PLAYBACK_STATE_CHANGED = SPOTIFY_PACKAGE + ".playbackstatechanged";
static final String METADATA_CHANGED = SPOTIFY_PACKAGE + ".metadatachanged";
}
}
and this is declared in my manifest:
<service
android:name=".BackgroundService"
android:enabled="true" >
<intent-filter>
<action android:name="com.spotify.music.playbackstatechanged" />
<action android:name="com.spotify.music.metadatachanged" />
<action android:name="com.spotify.music.queuechanged" />
</intent-filter>
</service>
So essentially my objective is to have my BackgroundService initialized when my app is opened, and to have it continue to run in the Background doing whatever I need it to do. As of now, I am using logs to determine whether my "setup" is working, but when I run my app, I am unable to see an logs even after I tested all actions that should have triggered my BroadCastReceiver. Furthermore, my persistent notification should have changed had my service been running, but it does not...
Edit::
So, I added logs to my BackgroundService's onCreate() and onReceive() methods, however, neither seem to be appearing. Im wondering, do I need to do something in my launcher activity to initialize the service? Furthermore, no notification is shown so I assume the Service is not being started for some reason...
Latest Edit:
So I added the following code to my Main activity to see if it would make a difference:
startService(new Intent(this,BackgroundService.class));
And after debugging my app, I began to see the following error:
java.lang.RuntimeException: Unable to create service com.aurum.mutify.BackgroundService: java.lang.SecurityException: Isolated process not allowed to call registerReceiver
pointing to my BroadCast Receiver class.

Intent services are designed for short tasks. And your intent handling method is empty.
If you need long running task in the background use standard service and call start foreground. This will minimize chance of system destroying your service.
To learn more go here
EDIT
Try overriding onStartCommand method. this method is called when service is started and usually you do all stuff here. Remember that there are 3 options to return.
Edit 2:
try something like this
in on create
PendingIntent pi;
BroadcastReceiver br;
Intent myIntent;
#Override
public void onCreate()
{
super.onCreate();
myIntent = new Intent("something")
if(Build.Version.SDK_INT >= 16) //The flag we used here was only added at API 16
myIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//use myIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); if you want to add more than one flag to this intent;
pi = PendingIntent.getBroadcast(context, 1, myIntent, 0);
br = new BroadcastReceiver ()
{
public void onReceive (Context context, Intent i) {
new thread(new Runnable()
{
public void run()
{
//do something
}
}).start();
}
};
And then in on start command
this.registerReceiver(br, new IntentFilter("something"));

Related

How to destroy/kill a service?

I have my application running a service for shake detect, however in my MainActivity, I have button for log out user, in which I must log out and terminate the service that detects the shake event.
my method for log out in my MainActivity is:
public void signOutAndFinish(){
//Stop Shakeservice
Intent intent = new Intent(this, ShakeService.class);
stopService(intent);
//Go to login activity
Intent iLoginView = new Intent(this, LoginActivity.class);
startActivity(iLoginView);
}
however if I shake my device after logging out, the service recognizes the shake, it is as if it will not kill it immediately:
Intent intent = new Intent(this, ShakeService.class);
stopService(intent);
The code in the method onDestroy is:
#Override
public void onDestroy() {
super.onDestroy();
}
How can I terminate the service so that when I log out the service dies?
Thanks for your help!
You can send a broadcast back your activity in the onDestroy() method of your service and then do the logout.
Here is some sample code of the above idea:
This for your service:
#Override
public void onDestroy() {
super.onDestroy();
Intent intent = new Intent();
intent.setAction("com.example.broadcast.MY_NOTIFICATION");
intent.putExtra("data","Notice for logout!");
sendBroadcast(intent);
}
And this is for your activity:
private BroadcastReceiver br = new MyBroadcastReceiver();
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter("com.example.broadcast.MY_NOTIFICATION");
registerReceiver(br, filter);
}
#Override
public void onDestroy() {
unregisterReceiver(br);
}
// An inner class at your activity
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
#Override
public void onReceive(Context context, Intent intent) {
YourActivity.this.finish();
// or do anything you require to finish the logout...
}
}
however if I shake my device after logging out, the service recognizes the shake
Then presumably you did not clean up your Sensor stuff in the service's onDestroy() method.
How can I terminate the service so that when I log out the service dies?
You are doing that now. However, if you set up something in the service, such as listening to events from SensorManager, you need to clean that up, typically in onDestroy() of the service.

Repetative and android service, self calling once complete

I am not sure if I have this right or not, but I have some code that I need to run in the background of my android application, and once that is complete, I would like to wait 10 seconds, and then run the code again.
I currently have this working, but I am sure it ain't the right way to go about it and wondered if someone can give me a simple example, or tell me what I need to change to make this "the right way" to do it.
First I have my ScheduleService.java file. This is where my code that I want to run it, and as you can see, once it is finished, it puts the thread to sleep for 10 seconds and then calls itself again, but this means that the code never actually completes (you should see the length of the stack trace if I get an error!)
ScheduleService.java
public class ScheduleService extends Service {
private static final String TAG = "ScheduleService";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
startJob();
}
});
t.start();
return Service.START_STICKY;
}
private void startJob(){
// all my code is here, and i do what i need
// job completed. Rest for 10 seconds before doing another one
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//do job again
startJob();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy(){
super.onDestroy();
}
}
Now to start the service code, I have the following when my application starts (in my MainActivity.java file)
// stop just encase its already started
context.stopService(new Intent(context, ScheduleService.class));
// start service
context.startService(new Intent(context, ScheduleService.class));
In order to make sure that the service is started when the device restarts, I also have my StartOnBootReciever.java code
public class StartOnBootReciever extends BroadcastReceiver {
private static final String TAG = "Autostart";
/**
* Listens for Android's BOOT_COMPLETED broadcast and then executes
* the onReceive() method.
*/
#Override
public void onReceive(Context context, Intent arg1) {
Log.d(TAG, "BOOT_COMPLETED broadcast received. Executing starter service.");
// upload in background
Intent intent = new Intent(context, ScheduleService.class);
context.startService(intent);
// This code will start the application once the device has been restarted
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
Then in my AndroidManifest.xml file, I have the following
<receiver android:enabled="true" android:exported="true" android:name="StartOnBootReciever" android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service android:enabled="true" android:exported="false" android:name="com.idamigo.ticketmachine.ScheduleService" />
This all works, but I feel that have code that is self-calling, and "never ending"
In your Service, you have used Thread.Sleep which is unnecessary. Because Service will run continuously in the background until you stop it or System stops it.
Example:
public class ScheduleService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Timer timer = new Timer();
timer.schedule(task,1,10000);
return Service.START_STICKY;
}
TimerTask task= new TimerTask() {
#Override
public void run() {
//do your task here.
}
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Go for Service only if you need to run a task continuously in the background. Otherwise, use IntentService. IntentService will be stopped when there is no work for it so you don't need to manage its state by yourself.

Android BroadcastReceiver inside service: issues

I am currently trying to create an Activity in Android with the capabilities of communicating with a started BroadcastReceiver inside of a service but I can't manage to do it well. I don't really know what the problem could be since (I think) I have followed all necessary steps.
In addition, I have other Activities which can communicate with this BroadcastReceiver without any problems. The code that I am using for the one I am having problems with is the following:
Registration of the name of the action in file ActivityList.java (Another activity):
public static final String ACTION1 = "com.test.ActionOne";
public static final String ACTION2 = "com.test.ActionTwo";
Registration of the actions with IntentFilter in the file GestTree.java which extends a Service:
Inside onCreate():
IntentFilter filter;
filter = new IntentFilter();
filter.addAction(ActivityList.ACTION1);
filter.addAction(ActivityList.ACTION2);
rec = new Receptor(); // This is a class which extends BroadcastReceiver
registerReceiver(receptor, filter);
Inside the function onReceive() of the private class Receptor of GestTree.java which extends BroadcastReceiver:
public final void onReceive(final Context context, final Intent intent) {
String action = intent.getAction();
if (action.equals(ActivityList.ACTION1)) {
Log.d(tag, "Test Passed!");
}
}
The definition of the service and the Activity State3Activity(the one I want to communicate with the service) in AndroidManifest.xml:
<activity
android:name="State3Activity"
android:label="#string/app_name" >
</activity>
<service
android:name="GestTree"
android:enabled="true"
android:label="#string/app_name" >
</service>
Code inside State3Activity.java:
public class State3Activity extends Activity {
Button mButton;
EditText editText_Name;
EditText editText_Desc;
private final String tag = this.getClass().getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.state3_layout);
mButton = (Button)findViewById(R.id.button_myButton);
editText_Nombre = (EditText)findViewById(R.id.editText_Name);
editText_Descripcion = (EditText)findViewById(R.id.editText_Desc);
mButton.setOnClickListener(
new View.OnClickListener()
{
public void onClick(View view)
{
Intent intent;
intent = new Intent();
intent.setAction(ActivityList.ACTION1);
// I have tried with all this combination of lines
// but none of them works
//intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
//intent.setClass(State3Activity.this, GestTree.class);
//intent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(intent);
}
});
}
There is where the problem comes. The intent never enters on the onReceive() function of the class when I press the button. What am I leaving?
Are you sure your service started? If you have not start the service, the method of onCreate() will not be executed, and the receiver will not be registed.

Broadcast Receiver not receiving

I know this question comes here fairly often, but I've looked through probably 20 stack overflow questions already and haven't been able to find a solution. I'm fairly certain it's something simple I'm doing wrong but I'm pretty new to Android and this assignment is due in 7 hours or so.
Everything works up until the receiver being called. Here's the call, from a service
Intent intent = new Intent(getApplicationContext(), MainActivity.WatchReceiver.class);
intent.putStringArrayListExtra(CHANGEKEY, changedURLs);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
Now here's the receiver, nested inside the main activity
public class WatchReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(null, "broadcast received");
markAsChanged(intent.getStringArrayListExtra(WatchService.CHANGEKEY));
}
}
And the main activity's on start function, where I register the receiver
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
wr = new WatchReceiver();
markedAsChanged = new ArrayList<Integer>();
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(wr, new IntentFilter());
Intent intent = new Intent(this, WatchService.class);
sc = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
wb = (WatchService.WatchBinder) service;
}
#Override
public void onServiceDisconnected(ComponentName name) {
wb = null;
}
};
bindService(intent, sc, Context.BIND_AUTO_CREATE);
}
Explicit Intents do not work with registerReceiver(), whether you are calling registerReceiver() on a Context (for system-level broadcasts) or on an instance of LocalBroadcastManager (for local broadcasts).
Instead:
Define an action string (e.g., final String ACTION="com.dellosa.nick.ITS_HUMP_DAY";)
Use that action string when creating the Intent to broadcast (new Intent(ACTION))
Use that action string when creating the IntentFilter (new IntentFilter(ACTION))

Android :: why getBooleanExtra java.lang.NullPointerException

PROBLEM
As topic mention, I don't know why getBooleanExtra() java.lang.NullPointerException.
I understand that sometimes intent may not contains extras.
However, from the below code as you can see there is a default value for each getBooleanExtra() which is false.
So, that's the reason why I don't understand. please advice. thx!
SOME CODE FROM MY SERVICE CLASS
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("onStartCommand()->","Intent Service.... " + intent);
final boolean SLEEP_MODE_ON = intent.getBooleanExtra("SLEEP_MODE_ON",false);
final boolean SLEEP_MODE_OFF = intent.getBooleanExtra("SLEEP_MODE_OFF",false);
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
connectIfNecessary();
if (SLEEP_MODE_ON){
doSleepMode_on();
} else if (SLEEP_MODE_OFF) {
doSleepMode_off();
}
}
});
thread.start();
return START_STICKY;
}
EDIT as some ask Where I call My service?? First, from activity. Second, from broadcastReceiver
ACTIVITY in onCreate()
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
startService(new Intent(this,mqttPushService.class)); //Setup MQTT Service
}//END of onCreate()
BroadcastReceiver
public class SleepModeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent sleepModeIntent;
int broadcastID = intent.getIntExtra("BROADCAST_ID",0);
switch (broadcastID) {
case DataManager.BROADCAST_ID_SLEEP_MODE_START :
sleepModeIntent = new Intent(context, mqttPushService.class);
sleepModeIntent.putExtra("SLEEP_MODE_ON",true);
context.startService(sleepModeIntent);
break;
case DataManager.BROADCAST_ID_SLEEP_MODE_STOP :
sleepModeIntent = new Intent(context, mqttPushService.class);
sleepModeIntent.putExtra("SLEEP_MODE_OFF",true);
context.startService(sleepModeIntent);
break;
}
}
}
I ran into this recently. The issue is that even services can be killed and restarted by the system , thats why you have START_STICKY. Unlike when you start the service and you pass a valid intent, when the system restarts the service, the intent is null. I just check for a null intent before trying to extract any extras.
Here is the link to the official android developers blog.
http://android-developers.blogspot.com/2010/02/service-api-changes-starting-with.html
and here is the paragraph which basically says what I say above
START_STICKY is basically the same as the previous behavior, where the service is left "started" and will later be restarted by the system. The only difference from previous versions of the platform is that it if it gets restarted because its process is killed, onStartCommand() will be called on the next instance of the service with a null Intent instead of not being called at all. Services that use this mode should always check for this case and deal with it appropriately.

Categories

Resources