Android O - Detect connectivity change in background -


first off: know connectivitymanager.connectivity_action has been deprecated , know how use connectivitymanager.registernetworkcallback. furthermore if read jobscheduler, not entirely sure whether got right.

my problem want execute code when phone connected / disconnected to/from network. should happen when app in background well. starting android o have show notification if want run service in background want avoid.
tried getting info on when phone connects / disconnects using jobscheduler/jobservice apis, gets executed time schedule it. me seems can't run code when event happens. there way achieve this? maybe have adjust code bit?

my jobservice:

@requiresapi(api = build.version_codes.lollipop) public class connectivitybackgroundserviceapi21 extends jobservice {      @override     public boolean onstartjob(jobparameters jobparameters) {         logfactory.writemessage(this, log_tag, "job started");         connectivitymanager connectivitymanager = (connectivitymanager) getsystemservice(context.connectivity_service);         networkinfo activenetwork = connectivitymanager.getactivenetworkinfo();         if (activenetwork == null) {             logfactory.writemessage(this, log_tag, "no active network.");         }else{             // here logic consuming whether device connected network (and type)         }         logfactory.writemessage(this, log_tag, "job done. ");         return false;     } } @override public boolean onstopjob(jobparameters jobparameters) {     logfactory.writemessage(this, log_tag, "job stopped");     return true; } 

i start service so:

jobscheduler jobscheduler = (jobscheduler)context.getsystemservice(context.job_scheduler_service); componentname service = new componentname(context, connectivitybackgroundserviceapi21.class); jobinfo.builder builder = new jobinfo.builder(1, service).setpersisted(true)     .setrequirednetworktype(jobinfo.network_type_any).setrequirescharging(false); jobscheduler.schedule(builder.build());             jobscheduler.schedule(builder.build()); //it runs when call - doesn't re-run if network changes 

manifest (abstract):

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools">      <uses-permission android:name="android.permission.internet" />     <uses-permission android:name="android.permission.receive_boot_completed" />     <uses-permission android:name="android.permission.access_network_state" />     <uses-permission android:name="com.android.launcher.permission.install_shortcut" />     <uses-permission android:name="android.permission.vibrate" />      <application>         <service             android:name=".services.connectivitybackgroundserviceapi21"             android:exported="true"             android:permission="android.permission.bind_job_service" />     </application> </manifest> 

i guess there has easy solution not able find it.

second edit: i'm using firebase's jobdispatcher , works perfect across platforms (thanks @cutiko). basic structure:

public class connectivityjob extends jobservice{      @override     public boolean onstartjob(jobparameters job) {         logfactory.writemessage(this, log_tag, "job created");         connectivitymanager = (connectivitymanager) getsystemservice(context.connectivity_service);         if (build.version.sdk_int >= build.version_codes.lollipop) {             connectivitymanager.registernetworkcallback(new networkrequest.builder().build(), networkcallback = new connectivitymanager.networkcallback(){                 // -snip-             });         }else{             registerreceiver(connectivitychange = new broadcastreceiver() {                 @override                 public void onreceive(context context, intent intent) {                     handleconnectivitychange(!intent.hasextra("noconnectivity"), intent.getintextra("networktype", -1));                 }             }, new intentfilter(connectivitymanager.connectivity_action));         }          networkinfo activenetwork = connectivitymanager.getactivenetworkinfo();         if (activenetwork == null) {             logfactory.writemessage(this, log_tag, "no active network.");         }else{             // logic..         }         logfactory.writemessage(this, log_tag, "done onstartjob");         return true;     }       @override     public boolean onstopjob(jobparameters job) {         if(networkcallback != null && build.version.sdk_int >= build.version_codes.lollipop)connectivitymanager.unregisternetworkcallback(networkcallback);         else if(connectivitychange != null)unregisterreceiver(connectivitychange);         return true;     }      private void handleconnectivitychange(networkinfo networkinfo){         // calls handleconnectivitychange(boolean connected, int type)     }      private void handleconnectivitychange(boolean connected, int type){         // calls handleconnectivitychange(boolean connected, connectiontype connectiontype)     }      private void handleconnectivitychange(boolean connected, connectiontype connectiontype){         // logic based on new connection     }      private enum connectiontype{         mobile,wifi,vpn,other;     } } 

i call (in boot receiver):

   job job = dispatcher.newjobbuilder().setservice(connectivityjob.class)             .settag("connectivity-job").setlifetime(lifetime.forever).setretrystrategy(retrystrategy.default_linear)             .setrecurring(true).setreplacecurrent(true).settrigger(trigger.executionwindow(0, 0)).build(); 

edit: found hacky way. hacky say. works wouldn't use it:

  • start foreground service, go foreground mode using startforeground(id, notification) , use stopforeground after that, user won't see notification android registers having been in foreground
  • start second service, using startservice
  • stop first service
  • result: congratulations, have service running in background (the 1 started second).
  • ontaskremoved get's called on second service when open app , cleared ram, not when first service terminates. if have repeating action handler , don't unregister in ontaskremoved continues run.

effectively starts foreground service, starts background service , terminates. second service outlives first one. i'm not sure whether intended behavior or not (maybe bug report should filed?) it's workaround (again, bad one!).


looks it's not possible notified when connection changes:

  • with android 7.0 connectivity_action receivers declared in manifest won't receive broadcasts. additionally receivers declared problematically receive broadcasts if receiver registered on main thread (so using service won't work). if still want receive updates in background can use connectivitymanager.registernetworkcallback
  • with android 8.0 same restrictions in place in addition can't launch services background unless it's foreground service.

all of allows these solutions:

  • start foreground service , show notification
    • this bothers users
  • use jobservice , schedule run periodically
    • depending on setting takes time until service get's called few seconds have passed since connection changes. in delays action should happen on connection change

this not possible:

  • connectivitymanager.registernetworkcallback(networkinfo, pendingintent) cannot used because pendingintent executes it's action instantly if condition met; it's called once
    • trying start foreground service way goes foreground 1 ms , re-registers call results in comparable infinite recursion

since have vpnservice runs in foreground mode (and shows notification) implemented service check connectivity runs in foreground if vpnservice doesn't , vice-versa. shows notification, one.
in find 8.0 update extremely unsatisfying, seems either have use unreliable solutions (repeating jobservice) or interrupt users permanent notification. users should able whitelist apps (the fact alone there apps hide "xx running in background" notification should enough). off-topic

feel free expand solution or show me errors, these findings.


Comments

Popular posts from this blog

angular - Ionic slides - dynamically add slides before and after -

minify - Minimizing css files -

Add a dynamic header in angular 2 http provider -