Abdullah Saad
Abdullah Saad

Reputation: 3

Broadcasts aren't being received upon clearing the recent task

I wanted to make an app that would do something upon receiving broadcast for wifi state changes. How to edit this code in such way that the service also receives broadcasts after clearing the recent task ? Please help.thanks

Here is the code below :

public class IntentService extends Service {
    SharedPreferences sharedPreferences;
    SimpleDateFormat simpleDateFormat;
    BroadcastReceiver broadcastReceiver= new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int wifiStateExtra=intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
            sharedPreferences.edit().putString(simpleDateFormat.format(new Date()),"  :"+ wifiStateExtra).apply();
                        Log.d("Wifi State", "  :"+wifiStateExtra +"   i :" +i);
        }
    };
    private int i;
    public IntentService() {
        super();
    }
    @Override
    public void onCreate() {
        super.onCreate();
        sharedPreferences = getSharedPreferences("test", MODE_PRIVATE);
        simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
    }
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        super.onStart(intent, startId);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        registerReceiver(broadcastReceiver, intentFilter);
    }
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        return START_STICKY;
    }
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Toast.makeText(getApplicationContext(), "onTaskRemoved called", Toast.LENGTH_LONG).show();
        startService(rootIntent);
        super.onTaskRemoved(rootIntent);
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

Upvotes: 0

Views: 68

Answers (2)

MIF50
MIF50

Reputation: 31

Nougat and Above: We have to use JobScheduler and JobService for Connection Changes.

All I can divide this into three steps.

Register JobScheduler inside activity. Also, Start JobService( Service to handle callbacks from the JobScheduler. Requests scheduled with the JobScheduler ultimately land on this service's "onStartJob" method.)

public class NetworkConnectionActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_network_connection);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        scheduleJob();

    }


    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void scheduleJob() {
        JobInfo myJob = new JobInfo.Builder(0, new ComponentName(this, NetworkSchedulerService.class))
                .setRequiresCharging(true)
                .setMinimumLatency(1000)
                .setOverrideDeadline(2000)
                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
                .setPersisted(true)
                .build();

        JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobScheduler.schedule(myJob);
    }

    @Override
    protected void onStop() {
        // A service can be "started" and/or "bound". In this case, it's "started" by this Activity
        // and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call
        // to stopService() won't prevent scheduled jobs to be processed. However, failing
        // to call stopService() would keep it alive indefinitely.
        stopService(new Intent(this, NetworkSchedulerService.class));
        super.onStop();
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Start service and provide it a way to communicate with this class.
        Intent startServiceIntent = new Intent(this, NetworkSchedulerService.class);
        startService(startServiceIntent);
    }
}

The service to start and finish the job.

public class NetworkSchedulerService extends JobService implements
        ConnectivityReceiver.ConnectivityReceiverListener {

    private static final String TAG = NetworkSchedulerService.class.getSimpleName();

    private ConnectivityReceiver mConnectivityReceiver;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "Service created");
        mConnectivityReceiver = new ConnectivityReceiver(this);
    }



    /**
     * When the app's NetworkConnectionActivity is created, it starts this service. This is so that the
     * activity and this service can communicate back and forth. See "setUiCallback()"
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
        return START_NOT_STICKY;
    }


    @Override
    public boolean onStartJob(JobParameters params) {
        Log.i(TAG, "onStartJob" + mConnectivityReceiver);
        registerReceiver(mConnectivityReceiver, new IntentFilter(Constants.CONNECTIVITY_ACTION));
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        Log.i(TAG, "onStopJob");
        unregisterReceiver(mConnectivityReceiver);
        return true;
    }

    @Override
    public void onNetworkConnectionChanged(boolean isConnected) {
        String message = isConnected ? "Good! Connected to Internet" : "Sorry! Not connected to internet";
        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();

    }
}

Finally, The receiver class which checks the network connection changes.

public class ConnectivityReceiver extends BroadcastReceiver {

    private ConnectivityReceiverListener mConnectivityReceiverListener;

    ConnectivityReceiver(ConnectivityReceiverListener listener) {
        mConnectivityReceiverListener = listener;
    }


    @Override
    public void onReceive(Context context, Intent intent) {
        mConnectivityReceiverListener.onNetworkConnectionChanged(isConnected(context));

    }

    public static boolean isConnected(Context context) {
        ConnectivityManager cm = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    }

    public interface ConnectivityReceiverListener {
        void onNetworkConnectionChanged(boolean isConnected);
    }
}

Don't forget to add permission and service inside manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.yourpackagename">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>


    <!-- Always required on api < 21, needed to keep a wake lock while your job is running -->
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <!-- Required on api < 21 if you are using setRequiredNetworkType(int) -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!-- Required on all api levels if you are using setPersisted(true) -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".connectivity.NetworkConnectionActivity"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>


        <!-- Define your service, make sure to add the permision! -->
        <service
            android:name=".connectivity.NetworkSchedulerService"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE"/>
    </application>

</manifest>

Please refer below links for more info. https://github.com/jiteshmohite/Android-Network-Connectivity

https://github.com/evant/JobSchedulerCompat

https://github.com/googlesamples/android-JobScheduler https://medium.com/@iiro.krankka/its-time-to-kiss-goodbye-to-your-implicit-broadcastreceivers-eefafd9f4f8a

Upvotes: 2

Rushikant Pawar
Rushikant Pawar

Reputation: 458

In Short :

Intended Behaviour

Is the one line answer to your question. You can try creating issue on https://issuetracker.google.com/

and you will get above as answer.

Bit longer answer :

Years by years Google has restricted so many capabilities of developers, under the issue of battery performance. In short No apps in background will be getting any any any broadcasts in short. And if you clears your app from recents, its gone out of execution forever, until end user opens the app again.

This is not just for broadcasts but also for background work / tasks / jobs / alarms / anything.. For these try using workmanager / tasks of your own / job schedular / alarm manager everything fails.

Why it all fails :

Workmanager is the latest library and as per google it is intended to deliver work at any cost as per system decides whenever it will be good to execute, in order to save battery. And as previous alarmmanager and others has a lot of problems in delivering tasks to be done.

Workmanager Which also fails as it has many bugs.. and is under development.

Does workmanager really works on most of the devices ?

Yes it does only on emulators, in market 98 % are chinese ROMS modified android devices which never run your processes.

What should you try, which will work ?

  1. I dont see unregister receiver on destroy.
  2. You must run a foreground service which implements registering receiver and unregistering it in ondestroy. And user START_STICKY.
  3. THIS IS THE ONLY POSSIBLITY

What should else be the way to be there ?

Use Firebase as framework and let google handle it. It notifies such states for sure like facebook, whatsapp, tiktok, twitter and all others use this as backend and even if removed from recents..!!

Upvotes: 0

Related Questions