I was trying to make my Service (foreground service) class a singleton like so:
object MyClass: Service() {
}
when I do this, I can't send an intent to start the service like this:
val mIntent = Intent(this, MyClass::class.java)
mIntent.action = MyClass.ACTION_START_FOREGROUND_SERVICE;
ContextCompat.startForegroundService(this, mIntent)
I get an IllegalAccessException, like this:
Caused by: java.lang.IllegalAccessException: void com.it.gy.MyClass.<init>() is not accessible from java.lang.Class<android.app.AppComponentFactory>
this exception is supposed to be caused when class at hand is not public, but, object MyClass is supposed to be so by default. I could make the class a public and make a private constructor to implement a custom singleton, but, I'd like to use the Kotlin syntax as far as possible. How may I do that?
What you want is not supported by the operating system. A Service needs to be a class, as Android will want to create an instance of that class.
Related
My app should do an stuff every morning. So I am using broadcast receiver. When broadcast receiver is triggered I need to connect to my room-db. Get some data and do stuff with them. Normally I am using AndroidViewModel and LiveData for that. But I can not initiate a AndroidViewModel inside BroadcastReceiver. Instead I am initiating my repository and sending a read reaquest and assigning them to LiveData.
Problem is I need to observe the live data. But Broadcast receiver is not an lifecycle-owner.
private void getData(){
HomeRepository repository = HomeRepository.getInstance(context);
alarms = repository.getAllAlarms();
alarms.observe(this, new Observer<List<Alarm>>() {
#Override
public void onChanged(List<Alarm> alarmList) {
//Do Stuff
}
});
}
So it gives me a compile error saying Broadcast Reciever is not a lifecyle owner
So I tried this:
public class MyBroadcastReceiver extends BroadcastReceiver implements LifecycleOwner
It compiled but gave an error on the run time
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.lifecycle.Lifecycle$State androidx.lifecycle.Lifecycle.getCurrentState()' on a null object reference
Can someone please show me the right direction to go here?
I am bit confused what is the right place to use Service (for background task).
This is my scenario:
I have a class that extends Broadcast receiver. It receives WiFi state changes. Depending on the state change, I call another class. This is a pure Java class, not extending any class.
This class is instantiated by passing the Context (received with the broadcast receiver).
I need to pass the Context because, among other things, I access SharedPreferences, display a notification, etc. But this not a foreground activity.
Is this the correct way? Or should my class extend Service and work as a background task?
Is it wrong to pass the Context to initiate a class?
For example,
public class WifiStateBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
...
WifiChangeReceptionClass wifiChanged = new WifiChangeReceptionClass(context);
wifiChanged.showNotification();
...
}
What is wrong with this approach?
Try any of this:
public class WifiChangeReceptionClass{
public static void showNotification(Context context){
//showYourNotification
}
}
Or
Create an Application class that has a static method to get it's context, like so.
public class MyApplication extends Application {
...
public static MyApplication get(){
return this;
}
...
}
Then in your class, just call:
public class WifiChangeReceptionClass{
public static void showNotification(){
Context context = MyApplication.get();
//showYourNotification
}
}
Or
Just use dagger for your dependency injections.
Check docs here
It is wrong because context reference will be available as long as you are in onReceive() method. Once call back onReceive() method gets completed context will no longer be available.
It is absolutely fine as long as you are using the context within the lifecycle of broadcast receiver (you may pass it to any class). Since broadcast receiver and service, both run on UI thread, using service would not make much difference.
If you want to perform some network operation or long running operation, then you can instantiate a intent service from receiver.
Registering for broadcast receiver to get Wifi state changes might not from Android 7 its has disabled the CONNECTIVITY_CHANGED.
Apps targeting Android 7.0 (API level 24) and higher do not receive CONNECTIVITY_ACTION broadcasts if they declare the broadcast receiver in their manifest. Apps will still receive CONNECTIVITY_ACTION broadcasts if they register their BroadcastReceiver with Context.registerReceiver() and that context is still valid.
This includes connectivity change. The better option is to use JobScheduler. Refer this link
As mentioned in the response, onReceive() of BroadcastReceiver is executed on main thread. Based on android documentation for broadcast receiver
As a general rule, broadcast receivers are allowed to run for up to 10 seconds before they system will consider them non-responsive and ANR the app. Since these usually execute on the app's main thread, they are already bound by the ~5 second time limit of various operations that can happen there (not to mention just avoiding UI jank), so the receive limit is generally not of concern. However, once you use goAsync, though able to be off the main thread, the broadcast execution limit still applies, and that includes the time spent between calling this method and ultimately PendingResult.finish().
If your WifiChangeReceptionClass is doing some extensive work, then refrain from running directly in onRecevie(). Instead start Service (you have to spawn a new thread thread) or IntentService
FYI This works in Native Android but i'm now porting it to Xamarin
I have created an IntentService that I wish to start from another application. So I need to be able to start the service via the Intent Filter method rather than by specifying the class directly.
E.g like so from an Activity:
Android.Content.Intent intent = new Android.Content.Intent("com.my.command");
StartService(intent);
My intent service class is properly decorated like so:
namespace Services{
[Service (Exported = true, Enabled = true)]
[IntentFilter(new[] { "com.my.command" })]
class DataIntentService : IntentService
{
protected void OnHandleIntent(Intent intent)
{
// this never fires!
}
}
}
If I extend Service rather than IntentService it works fine, but I want to use IntentService!
Any ideas why this not working? By the way, I haven't even attempted to send this Intent from an external application yet, this is from within the same application.
Thanks
Thanks to a good bit of help I got from someone in my last question I am further ahead then before. Now I need to figure out how make this broadcast into a service. Or do I need to make a 3rd file and make a service out of that class?
Any help would be cool!
create a class which extends Service.
public class myService extends Service{
and use the Application Context object passed to your BroadcastReceiver to start the service.
context.startService(intent);
If you need to carry data over from your Intent object put a set of extras into the Intent object you create when you call
sendBroadcast(Intent intent);
I have a Service that can be stopped in multiple ways. Whenever I call stopService(Intent), I pass an intent with some extras. How do you retrieve those extras?
Thanks.
You need to override onStartCommand() in your Service this is how you get a reference to the incoming intent from startService.
In this case you would have a special action in your intent to tell the service to stop itself. You add extras to this intend which can be read in the onStartCommand() method.
Sample Code
public class MyService extends Service {
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
final String yourExtra = intent.getStringExtra(YOUR_EXTRA_ID);
// now you can e.g. call the stopSelf() method but have the extra information
}
}
Explanation
Every time you call context.startService(Intent) onStartCommand() will be called. If the service is already running a new service isn't created but onStartCommand is still called. This is how you can get a new intent with extras to a running service.
I found that the extras are not passed with the intent when stopService is called. As a workaround, simply call startService(Intent) and stopService(Intent) right after one another.
Example code from Activity:
Intent j = new Intent(SocketToYa.this, AccelerometerDataSocket.class);
j.putExtra("com.christophergrabowski.sockettoya.DestroyService", true);
startService(j);
stopService(j);
In Service.onStartCommand,
intent.hasExtra("com.christophergrabowski.sockettoya.DestroyService")
will evaluate to true, and you will destroy your service the way intended by the API (i.e., by calling stopService, which will in turn call OnDestroy after onStartCommand is called).
My suggetion is that use static member in class that extends Activity for passing information to service & it in service as normal static member access in outside class
Please don't do this unless you have no other option. You should try to use the mechanisms built into the framework for passing data, and not use public static fields unless there is no other choice. Read the Service documentation for examples.
Are you able to use an Intent with a "shutdown" action with Context.startService()?
That is, send an Intent with a shutdown action and extras to Service.onStartCommand(), decide how to shutdown based on the extras, then use Service.stopSelf() to stop the service.
I agree this isn't a great solution, since it potentially starts the service in order to shut it down. I would still like to hear of the "correct" way (if one exists) of doing this with Context.stopService().
You can not write
getIntent()
method in a class extending Service. So I think using getExtra() won't work.
My suggetion is that use static member in class that extends Activity for passing information to service & it in service as normal static member access in outside class i.e.
Classname.yourobject
.
see this link for other option
http://developer.android.com/resources/faq/framework.html#3