So my Main activity in my Android app is about 500 lines and some change. I am refactoring it and abstracting out as many components as I can. One of the components that take up a lot of space are my various custom buttons and their listeners. I want to get these (currently nested classes) into separate files and abstract the component so it's easier to integrate into other fragments, etc. This is converse to the common implementation of using listener interfaces, and implementing those in each activity/fragment.
The first obvious issue that I'm coming across is communicating back to the activity/fragment where the class instance is defined in order to update member variables. For example, my button increments and decrements a number, and I need to update that number in the respective parent context.
My first idea is that I need some sort of (weak) reference to that activity/fragment. If I intend to interact with a fragment, then in that case I would have to store another identifying parameter to my constructor and access the Fragment instance later via the parent activity.
My second thought is to instead handle the data updating via an external ViewModel. My main concern for this, however, is that this middle layer (and the resulting observable) will be too slow for a fast updating functionality like a press-and-hold button that speeds up the increment/decrement action (not mentioned here, but handled in another thread).
Here's an example of how I think this setup would look like (at least for option 1 above):
public class MainActivity extends AppCompatActivity {
private int myData;
Button inc;
Button dec;
@Override
protected void onCreate(Bundle savedInstanceState) {
inc = findViewById(R.id.inc);
dec = findViewById(R.id.dec);
CustomListener myListener = new CustomListener(getContext());
inc.setOnClickListener(myListener);
dec.setOnClickListener(myListener);
}
public incrementData() { myData++; }
public decrementData() { myData--; }
}
public class CustomListener implements View.OnClickListener {
private static WeakReference<MainActivity> activity;
public CustomListener(Activity activity) {
this.activity = new WeakReference<MainActivity>(activity);
}
@Override
public void onClick(View view) {
// If a Fragment was intended here, I'll have to somehow find this out via another
// parameter, then grab the Fragment and use it here instead of the root activity
if (view.getId() == R.id.increment) activity.increment();
else context.decrement();
}
}
What do others do in this situation? What's the "industry standard" for separating custom buttons and custom listeners from your Activity? I'm striving to make my personal project's code-base clean and tidy.
I ended up opting for my second idea from my question. That is I created a ViewModel
to update the data from the listener, then the observing Activity/Fragment can get the data when it updates.
As far as interacting with the ViewModel, I passed the encompassing activity/Fragment's this
context as a parameter to my class, so I could use it when defining the ViewModelStoreOwner
property of the ViewModelProvider
.
It seems to be working very effectively, and no UI lag at all from fast repeated updates to the model.