2

In my app, I have a working code that feels clumsy and I would like to optimize it. I have a form with several EditText controls. Some of them open another fragment, where the user picks stuff and returns to the main fragment. The communication was handled via interfaces, data in bundles and a main fragment that was reused via oFragment = (MainFragment) getSupportFragmentManager().findFragmentByTag(MainFragmentTag); I only used viewmodels to store and fetch data from databases. After the user made his selections, I would read the text contents of the controls and save them in a new entry POJO that got stored in the database.

Now I found out about using Shared ViewModels to store transient data and share it between fragments. If you can pick items from a list, it is really simple to implement (from android architecture components):

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}


public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, item -> {
           // Update the UI.
        });
    }
}

I think this could be used to store TextEdit data as well. I would feel more comfortable with UI data being stored in viewmodels instaed of reading usercontrols during the save process - from what I now about android lifecycles, this UI data will be lost if the user rotates the screen. And I would get rid of bloat code to reuse the same main fragment instance.

My implementation of using Viewmodels to chache EditText data is posted below and works, but it seems quite clumsy. Can you recommend me a best pattern way to do it? Or do I worry to much and SavedInstanceState will always keep stuff the user typed in editTexts? Below is my code:

In main fragments OnCreateView:

if (oStandardModel.getSelected().getValue() != null && !oStandardModel.getSelected().getValue().isEmpty()){
        oBinding.EditNumber.setText(oStandardModel.getSelected().getValue());
    }

    oBinding.EditNumber.addTextChangedListener(new Manager.TextValidator(oBinding.EditNumber) {
        @Override public void CacheIfValid(TextView textView, String text) {
            if (text != null && !text.isEmpty() && Manager.isNumeric(text)){
                oStandardModel.type(text.replaceAll(",", "."));
            }
        }
    });

CacheifValid is inspired by a class I stole from here. It was meant for text validation, but I abuse it to store user entried data (Class within a utility class called "manager"):

public static abstract class TextValidator implements TextWatcher {
    private final TextView textView;

    public TextValidator(TextView textView) {
        this.textView = textView;
    }

    public abstract void CacheIfValid(TextView textView, String text);

    @Override
    final public void afterTextChanged(Editable s) {
        String text = textView.getText().toString();
        CacheIfValid(textView, text);
    }

    @Override
    final public void beforeTextChanged(CharSequence s, int start, int count, int after) { /* Don't care */ }

    @Override
    final public void onTextChanged(CharSequence s, int start, int before, int count) { /* Don't care */ }
}

The relevant fields in the ViewModel class look like this:

private final MutableLiveData<String> selected = new MutableLiveData<String>();

public void type(String item) {
    selected.setValue(item);
}

public MutableLiveData<String> getSelected() {
    return selected;
}

Thanks for reading so far!

Apfelsaft23
  • 316
  • 2
  • 23

0 Answers0