I made an application with: an activity (MainActivity) that starts a service (SmartphoneListener).
Activity
public class MainActivity extends Activity implements GoogleApiClient.ConnectionCallbacks{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,SmartphoneListener.class);
startService(intent);
}
}
The service is used to detect (on smartphone) if the connection with smartwatch is lost.
Service
public class SmartphoneListener extends WearableListenerService {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag"); //Service running even if the screen is off.
wakeLock.acquire();
return START_STICKY;
}
#Override
public void onPeerDisconnected(Node node){
Toast.makeText(getApplicationContext(),"Communication with smartwatch lost",Toast.LENGTH_SHORT).show();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
registerReceiver(mIntentReceiver, filter);
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent) {
//
}
};
...
}
If my application is open and the smartphone screen is off I can detect if I lost my connection with smartwatch (the mIntentReceiver code is executed).
Then If I close my application and the smartphone screen is off I can't detect if I lost my connection with smartwatch (the mIntentReceiver code is not executed).
I don't know why.
Try to add
filter.addAction(Intent.ACTION_SCREEN_OFF);
to your IntentFilter. Hope it help!
You explained in the reply to my comment that you are "closing" the app by swiping it from the recent tasks list. This action causes the process for your app to be killed. Because you return START_STICKY from onStartCommand() in your service, the system will create a new instance of your app in a new process and call onStartCommand() to restart your service. That is the only entry made into your app. No activities are recreated. I know very little about Wear. I'm guessing that your app performs some configuration processing to locate and connect to nodes. If that processing is done in some activity, such as your launch activity, it will not be performed when your app is recreated to restart your service.
Related
I'm trying to create an autorun service: so that the application launches every time after unlocking the screen, after entering the graphic key or password if it exists (on Android 7,8,9,10). I wrote the code dynamically through the borocast receiver (ACTION_SCREEN_OFF) but it works while the application is on the stack (running) and I want it to always start. The method through registering in the manifest in android 9 already does not work the listeners. How to implement this?
public class WordsBase extends AppCompatActivity {
ScreenReceiver resiverStart;
#Override
protected void onPause() {
super.onPause();
resiverStart= new ScreenReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(resiverStart,filter);
}
}
public class ScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Intent intent1 = new Intent(context, WordsBase.class);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent1);
}
throw new UnsupportedOperationException("Not yet implemented");
}
}
I understand that you want to do the following:
If the user unlocks the device, you want to start your app.
Why don't you do the following:
Use the USER_PRESENT receiver (android.intent.action.USER_PRESENT). Please not that you have to register explicitly to this receiver, just registering it in the manifest is not enough
If the respective broadcast is fired, start your app and make sure you are still registered to the broadcast (to have your app started again the next time the user unlocks the device).
I need to have a two way communication between my activity and a running IntentService.
The scenario is like this: the app can schedule alarms which on run, start an IntentService which fetches some data from web and process it. There are three possible situations when IntentService finishes:
The app is in focus, which means that when the IntentService will finish, the app needs to refresh its views with the new data.
The app is closed and when opened after IntentService has finished the work, so the app will have access to processed data
The app is opened while the IntentService is running, in which case I need to have a way from the activity to ask the IntentService if its doing something in the background.
For 1. I have already implemented a BroadcastReceiver in my activity which gets registered with the LocalBroadcastManager. When IntentService finishes the work, sends a broadcast and the activity reacts. This works fine
For 2. There is nothing needed to be done
For 3. I don't know what to do. So far I've tried this:
In Activity:
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_SEND_TO_SERVICE));
In IntentService
private LocalBroadcastManager localBroadcastManager;
private BroadcastReceiver broadcastReceiverService = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BROADCAST_SEND_TO_SERVICE)) {
//does not reach this place
//Send back a broadcast to activity telling that it is working
}
}
};
#Override
protected void onHandleIntent(Intent intent) {
localBroadcastManager = LocalBroadcastManager.getInstance(context);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_SEND_TO_SERVICE);
localBroadcastManager.registerReceiver(broadcastReceiverService, intentFilter);
.... //do things
}
The problem with my implementation is that n the IntentService the BroadcastReceiver does not fire onReceive. Any suggestions or maybe a simpler way for the Activity to ask the IntentService what it is doing?
LE:
Trying to get atomicboolean.
In Service:
public static AtomicBoolean isRunning = new AtomicBoolean(false);
#Override
protected void onHandleIntent(Intent intent) {
isRunning.set(true);
// do work
// Thread.sleep(30000)
isRunning.set(false);
}
In Activity, restarting the app while service is running:
Log(MyIntentService.isRunning.get());
//this returns always false, even if the intent service is running
On AndroidManifest
<service
android:name=".services.MyIntentService"
android:exported="false" />
I am having problem with my android IntentService. When I first open the application, the service gets started by intent from the profile activity and data is fetched from this service. If I switch to other activity and then back service is still running and that is ok.
However if you press back, so that activity is finished and put in the background, the service is still working as the application is in background but If I get it back to foreground service stops. I do not know why. Bellow is my code, please help.
I have read activity life cycle couple of times and still do not get it why this is happening.
What is weird is that Service receive data one more time before it stops when MainActivity is brought back to running state. Service is not crashing.
Service
public class SomeService extends IntentService
{
public static final String extra = "someData";
public SomeService()
{
super(SomeService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent)
{
Log.e("SomeService", "starting service");
while (true)
{
SomeData data = Api.getNewSocketData();
//Broadcast data when received to update the view
Intent broadcastData = new Intent();
broadcastData.setAction(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
broadcastData.addCategory(Intent.CATEGORY_DEFAULT);
broadcastData.putExtra(extra, " ");
sendBroadcast(broadcastData);
Log.e("SomeService", "received from socket");
}
}
}
Receiver
public class dataBroadcastReceiver extends BroadcastReceiver
{
public final static String ACTION_DATA_RECEIVED = "net.bitstamp.intent.action.ACTION_SOMEDATA_RECEIVED";
#Override
public void onReceive(Context context, Intent intent)
{
Log.e("receiver", "data received");
}
}
Main Activity
#Override
public void onPause()
{
super.onPause();
unregisterReceiver(dataBroadcastReceiver);
}
#Override
public void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
dataBroadcastReceiver = new dataBroadcastReceiver();
registerReceiver(dataBroadcastReceiver, intentFilter);
Intent someService = new Intent(this, SomeService.class);
startService(someService);
}
I really need help on this. Thanks
You don't want to the up the IntentService in an infinite loop. It will block all other incoming requests. From the documentation:
All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
Your Service is likely still happily running along, it just isn't processing your new request because your old one is still being handled in the infinite loop.
I created a BroadcastReceiver and it runs only when my app shown in recent apps menu. If I remove my app from the recent apps the BroadcastReceiver will stop working.
How can I keep the BroadcastReceiver in background?
I register the BroadcastReceiver from my main activity (in OnCreate()).
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(receiver, intentFilter);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
This is not how you should register a receiver. You receiver stops working, because you construct it in onCreate, which means it will live as long as your app is alive. When the app gets destroyed, you also lose the the receiver.
If you register receiver inside an activity, you should always register it in onResume and deregister onPause, which will make it available while the activity is visible to the user. This is a use case when you want to have an active receiver while user interacts with an activity.
If you want a background receiver, you need to register it inside the AndroidManifest (with intent filter), add an IntentService and start it when you receive a broadcast in the receiver.
Here is a tutorial, you are interested in chapter 3.
If you need to be always on, start a foreground service. There is function in Service that lets you: startForeground. Then register your receiver when service is created and deregister when it's destroyed. Foreground services are quite nasty though.
Use a service with it.
Services can survive when the app dies if they have the right flag example:
public class MyService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY; //this defines this service to stay alive
}
#Override
public void onCreate() {
super.onCreate();
appStatus = APPISUP;
//This is a thread that stays alive for as long as you need
new CheckActivityStatus().execute();
//Not needed but in case you wish to lauch other apps from it
}
private class CheckActivityStatus extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
while(true) {
... //add something that breaks eventually
}
}
}
To lauch the service you have to lauch it from an activity like so:
Intent service = new Intent(getBaseContext(), MyService.class);
startService(service);
With the service the BroadcastReceiver still functions receiving whatever you want.
Note that the service sometimes stops and comes back. I haven't found out why but I'm betting on priorities of other apps that may ask the system to halt the service
I have a simple widget that does some calculations once the screen comes on and displays them and clears all the fields once the screen goes off ... i have a broadcast receiver setup in my service which listens to ACTION_SCREEN_ON and ACTION_SCREEN_OFF.
This works perfectly as long as the phone doesn't go to sleep for a long period of time or there is heavy usage of the phone - once this happens my widget process is killed (the service is still running but the process is killed) after this when the screen goes off and comes back on my widget doesn't update as the ACTION_SCREEN_ON intent is not caught by my service :(
public class CDTservice extends Service {
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
m_receiver = new ScreenBroadcastReceiver();
registerReceiver(m_receiver, filter);
Log.d("Widgettool", "works");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
start();
Toast.makeText(getBaseContext(), "SERVICE ON", Toast.LENGTH_SHORT).show();
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
stop();
unregisterReceiver(m_receiver);
}
public void start()
{
RemoteViews View = new RemoteViews(this.getPackageName(), R.layout.main);
updatewidgetclass x= new updatewidgetclass(this, View, widgetId);
x.start(); // does calculations and displays on widget
}
public void stop()
{
RemoteViews Viewclear = new RemoteViews(this.getPackageName(), R.layout.main);
updatewidgetclass y = new updatewidgetclass(this, Viewclear, widgetId);
y.stop(); // clears resources and stops
}
private class ScreenBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Log.d("ON SCREEN ON", "might hang here");
start();
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
stop();
}
}
}
sometimes when the widget process is not claimed by the android system the widget works perfectly for days and perfectly displays the values ACTION_SCREEN_ON
the problem arises when - i check in settings>apps>running - i can see my widget name and it says 0 processes and 1 service
i assume the broadcast receive is happening on the main process and hence its not receiving it when the process gets killed.
I have a work around in place for this but would really like to fix the issue.
Any helps is highly appreciated
I agree with #CommonsWare that having a service running in the bg at all times just to detect when the screen turns on and off is a very bad idea. Do you really need ACTION_SCREEN_ON, or will ACTION_USER_PRESENT (phone unlocked) suffice? This way, you do not need a service at all, and you can just define the receiver in the manifest.
If you really wanted to, you could register your service/ACTION_SCREEN_OFFreceiver in your ACTION_USER_PRESENT receiver so that the service is only running when the user is actually using the device.
I know this doesn't really answer your question, but it does provide a useful workaround to your problem.