Search code examples
androidmvvmbroadcastreceiverandroid-livedata

how to broadcast Receiver and MVVM?


my manifest

<receiver android:name=".ui.receiver.NetworkChangeReceiver" >
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                <action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
            </intent-filter>
        </receiver>

and NetworkChangeReceiver Class

class NetworkChangeReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val connMgr = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val activeNetwork: NetworkInfo? = connMgr.activeNetworkInfo
        val isConnected: Boolean? = activeNetwork?.isConnected


        if(isConnected == null) {
            Timber.d("Test Checked is Connected null ")

        } else {
            Timber.d("Test Checked Network is Connected !! ")
        }
    }
}

I going to detect the network here.

If my mainViewModel detects what I've detected here, I'm trying to bring up an image, but I don't know what to do

Image is being visualized using live data and if the network changes here, I want to change the visibility of the image in my MainView Model.


Solution

    1. define base class for LiveData of BroadcastReceiver
    public class ReceiverLiveData<T> extends LiveData<T> {
    
        private final Context context;
        private final IntentFilter filter;
        private final BiFunction<Context, Intent, T> mapFunc;
    
        public ReceiverLiveData(Context context, IntentFilter filter, BiFunction<Context, Intent, T> mapFunc) {
            this.context = context;
            this.filter = filter;
            this.mapFunc = mapFunc;
        }
    
        @Override
        protected void onInactive() {
            super.onInactive();
            context.unregisterReceiver(mBroadcastReceiver);
        }
    
        @Override
        protected void onActive() {
            super.onActive();
            setValue(mapFunc.apply(context, new Intent()));
            context.registerReceiver(mBroadcastReceiver, filter);
        }
    
        private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                setValue(mapFunc.apply(context, intent));
            }
        };
    }
    
    1. declare your variable in ViewModel, for example battery change intent
        public static class ViewModel extends AndroidViewModel {
            public final LiveData<Intent> batteryIntentLiveData = new ReceiverLiveData<>(getApplication(), new IntentFilter(Intent.ACTION_BATTERY_CHANGED), (context, intent) -> intent);
            public final LiveData<NetworkInfo> activeNetworkInfoLiveData = new ReceiverLiveData<>(getApplication(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION), ((context, intent) -> ((ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE)).getActiveNetworkInfo()));
    
            public ViewModel(@NonNull Application application) {
                super(application);
            }
        }
    
    1. initialize ViewModel in Activity::onCreate
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
            binding.setViewModel(new ViewModelProvider(this).get(ViewModel.class));
            binding.setLifecycleOwner(this);
            setContentView(binding.getRoot());
        }
    
    1. use batteryIntentLiveData & activeNetworkInfoLiveData in your DataBinding layout
    <?xml version="1.0" encoding="utf-8"?>
    <layout>
    
        <data>
    
            <variable
                name="viewModel"
                type="com.xxx.receiverbindingtest.MainActivity.ViewModel" />
    
            <import type="android.os.BatteryManager" />
    
            <import type="android.view.View" />
        </data>
    
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            tools:context=".MainActivity">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{String.valueOf(viewModel.batteryIntentLiveData.getIntExtra(BatteryManager.EXTRA_LEVEL, 0))}" />
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text='@{viewModel.batteryIntentLiveData.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0 ? "Charging" : "Discharging"}' />
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text='@{String.valueOf(viewModel.activeNetworkInfoLiveData.state)}'
                android:visibility="@{viewModel.activeNetworkInfoLiveData.connectedOrConnecting ? View.VISIBLE : View.GONE}" />
    
        </LinearLayout>
    </layout>