- Instance State Restoration
- Navigation b/w fragment or views in so-called navigation components way.
- Basic viewmodels should be attached to fragment/view that has lifecycle of activity-retained scope.
- Service locator/DI for simple apps that works at Singleton Component and ActivityRetainedComponent.
- [Pro-point] You can control your navigator from viewModel, so no more dependence on channelFlow for such basic action.
- Make a new Activity[SimpleStackMainActivity.java].
class SimpleStackMainActivity extends AppCompatActivity{
onCreate(){
DefaultFragmentStateChanger fragmentStateChanger = new DefaultFragmentStateChanger(getSupportFragmentManager(), R.id.container);
Navigator.configure().setStateChanger(new SimpleStateChanger(this)).setScopedServices(new DefaultServiceProvider()).install(this, binding.container, History.single(HomeKey.create()));
}
}
Important Note: History.single(HomeKey.create())
is actually clearing up the backstack and HomeKey class as First Navigation Destination for more look at setHistory api(s).
- Make your
BaseApplication.java
like :
class MyApplication extends Application{
private GlobalServices globalServices;
onCreate(){
//Defines a singleton components with singleton dependencies. This is maindatory for to run scoped services, which we will be using for lightweight viewModel.
globalServices = GlobalServices.builder().addService("RecordDatabase", RecordDatabase.getInstance(sApplication)).build();
}
}
- Adding Fragment to the activity having FrameLayout or FragmentContainerView(ig...)
a. Fragment Key
@AutoValue
public abstract class HomeKey extends FragmentKey {
public static HomeKey create() {
//This should be generated by AutoValue.. If not, rebuild your project.
return new AutoValue_HomeKey();
}
@StringRes
@Override
public int getTitle() {
return R.string.app_name;
}
@NonNull
@Override
protected Fragment instantiateFragment() {
//Create a single instance of fragment, simple stack will inflate it.
return new HomeFragment();
}
@Override
public void bindServices(@NonNull ServiceBinder serviceBinder) {
//Just leave this line if you don't want to use viewModel.
serviceBinder.addService(HomeViewModel.class.toString(), new HomeViewModel());
}
}
b. Fragment class
@AndroidEntryPoint //You can use hilt for field injection in normal way...
public class HomeFragment extends KeyedFragment {
private static String TAG = "HomeFragment";
@Inject
FirebaseAuth auth;
public HomeFragment() {
super(R.layout.activity_main);
}
@SuppressLint("SetTextI18n")
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding = ActivityMainBinding.bind(view);
}
}
c. ViewModel(via Scoped Service)
public class HomeViewModel implements ScopedServices.Activated {
private static String TAG = "HomeViewModel";
private final MutableLiveData<ViewModelState> _states = new MutableLiveData<>();
public final LiveData<ViewModelState> state = _states;
//This function will be called when the viewModel will start
@Override
public void onServiceActive() {
_states.postValue(new ViewModelState.Loading());
HomeViewModelEntryPoint entryPoint = EntryPoints.get(getContext(), HomeViewModelEntryPoint.class);
auth = entryPoint.getAuth();
}
//This function will be called when the viewModel will end
@Override
public void onServiceInactive() {
reg.remove();
}
//To Use hilt in scoped service you need to make new entry points
@InstallIn(SingletonComponent.class)
@EntryPoint
interface HomeViewModelEntryPoint {
FirebaseAuth getAuth();
}
}
Navigator.getBackstack(requireContext()).goTo(RecordKey.create());
Navigator.getBackstack(requireContext()).goBack();