Fetching methods from BroadcastReceiver to update

2019-07-21 22:56发布

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"));

2条回答
相关推荐>>
2楼-- · 2019-07-21 23:29

I think a nice way to handle something like this is with an eventbus.

Take a look at Squares Otto library.

In your broadcast receiver you would publish the change event and then in your activity you would subscribe to the event and update the ui.

Based on the context of your question, I think you would be able to avoid the broadcast receiver entirely, since I suspect you have something watching your provider and then broadcasting the event.

Update: (based on comments)

I think the way this would work would be something like this

In the code that detects the change in location provider:

if (bothProvidersAreStopped()) {
   bus.publish(new BothProvidersStoppedEvent());
} else if (onlyNetworkProviderIsStopped() {
   bus.publish(new NetworkProviderStoppedEvent());
} else if (onlyGpsProviderIsStopped() {
   bus.publish(new GpsProviderStoppedEvent());
}

in your activity

@Subscribe public void onBothProvidersStopped(BothProvidersStopped event) {
    // handle case were both providers just stopped
}

@Subscribe public void onNetworkProvidersStopped(BothProvidersStopped event) {
    // handle case were network provider just stopped
}

@Subscribe public void onGpsProvidersStopped(BothProvidersStopped event) {
    // handle case were gps provider just stopped
}
查看更多
萌系小妹纸
3楼-- · 2019-07-21 23:38

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);
            }
        });
    }
}
查看更多
登录 后发表回答