Search code examples
javaandroidstaticbroadcastreceiver

Fetching methods from BroadcastReceiver to update UI


I am trying to update the UI according to change of a variable in BroadcastReceiver. Thus, I need to call a method (to get the variable I mentioned) of a class which extends BroadcastReceiver in MainActivity depending on but I cannot get the true return value in any way.

The class which extends BroadcastReceiver is this:

public class ProviderChangeReceiver extends BroadcastReceiver {

    private static boolean isProviderActive;
    @Override
    public void onReceive(Context context, Intent intent) {
        LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            Log.v("-> ", "GPS + NETWORK");
            isProviderActive = true;
        }

        else if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && !lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            Log.v("-> ", "GPS");
            isProviderActive = true;
        }

        else if (lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) && !lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            Log.v("-> ", "NETWORK");
            isProviderActive = true;
        }

        else
        {
            Log.v("-> ", "DISCONNECT");
            isProviderActive = false;
        }
    }

    public static boolean isProviderActive(){
        return isProviderActive;
    }
}

I need to get true value of isProviderActive to use in this part of MainActivity:

...
private class ProviderChangeReceiver_updateUI extends ProviderChangeReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        MapsActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.v("-A", ""+ isProviderActive());
                if (isProviderActive())
                    originButton.setVisibility(View.VISIBLE);
                else
                    originButton.setVisibility(View.INVISIBLE);
            }
        });
    }
}

I know that indicating isProviderActive as static is not a good approach but I just want to observe its changes. As you guess, I got nonsensical return values all the time. To values of boolean isProviderActive without problem, what do you advise?

Edit: My temporary solution to update UI according to changes in BroadcastReceiver.

Forget about creating a separate class for ProviderChangeReceiver. Instead of the code segment above, following segment should be added in MainActivity. Also, it goes without saying that there is the initialization of ProviderChangeReceiver in onCreate().

...
private class ProviderChangeReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        MapsActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.v("COUNT: ", "" + count++);
                if (isLocationProviderActive()) {
                    originButton.getBackground().setAlpha(220);
                    originButton.setEnabled(true);
                    //marker.setVisible(true);
                }
                else {
                    originButton.getBackground().setAlpha(77);
                    originButton.setEnabled(false);
                    marker.setVisible(false);
                }
            }
        });
    }
}

private boolean isLocationProviderActive(){
    if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
        return true;
    return false;
}

Of course then register the receiver in onCreate() as well:

registerReceiver(pcr, new IntentFilter("android.location.PROVIDERS_CHANGED"));

Solution

  • The reason that every time isProvidrActive changed the whole activity got regenerated is because I sent the intent using context.startActivity(i) but rather this time we send the intent using contect.sendBroadcast(i) to the ProviderChangeReceiver_updateUI inner class which update only desired part of the UI. So below is the new code.

    private static boolean isProviderActive;
    @Override
    public void onReceive(Context context, Intent intent) {
        LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            Log.v("-> ", "GPS + NETWORK");
            isProviderActive = true;
        }
    
        else if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && !lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            Log.v("-> ", "GPS");
            isProviderActive = true;
        }
    
        else if (lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) && !lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            Log.v("-> ", "NETWORK");
            isProviderActive = true;
        }
    
        else
        {
            Log.v("-> ", "DISCONNECT");
            isProviderActive = false;
        }
    
        //Send value of isProviderActive to ProviderChangeReceiver_updateUI
        Intent i = new Intent(context, ProviderChangeReceiver_updateUI.class);
        i.putExtra("isProvidrActv", isProviderActive);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.sendBroadcast(i);
    }
    

    Edit your manifest file to enable the inner class ProviderChangeReceiver_updateUI to listen for broadcast sent by our broadcastReciever, add the following entry to manifest

    <receiver  android:name="<package-name>.MainActivity$ProviderChangeReceiver_updateUI"
                android:enabled="true" >
                <intent-filter>
                </intent-filter>
            </receiver>
    

    the $ sign indicates inner class. No need to add intent-filters unless required.

    And in your ProviderChangeReceiver_updateUI class in the onReceive() method get the value of isProviderActive

    ...
    //changed the identifiers from private to public static and the class extends //BroadcastReceiver
    public static class ProviderChangeReceiver_updateUI extends BroadcastReceiver {
    
        //Empty constructor to prevent exception can't instantiate no empty constructor
        public ProviderChangeReceiver_updateUI(){
    
        }
    
        //Removed the final keyword from handler
        private Handler handler; // Handler used to execute code on the UI thread
    
        public ProviderChangeReceiver_updateUI(Handler handler) {
            this.handler = handler;
        }
    
        @Override
        public void onReceive(final Context context, final Intent intent) {
            boolean isProvidrActv = intent.getBooleanExtra("isProvidrActv", false);
            //mapsActivity is a global static object of the class MapsActivity<br/>
            //instantiate it the onCreate() method of mainactivity for ex:<br/>
    /*public class MapsActivity extends Activity{<br/>
             static MapsActivity mapsActivity;
    
             @Override
             protected void onCreate(Bundle savedInstancestate){
            ma  = new MapsActivity();
            }*/
            mapsActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (isProvidrActv)
                        originButton.setVisibility(View.VISIBLE);
                    else
                        originButton.setVisibility(View.INVISIBLE);
                }
            });
        }
    }