코드는 거의 다 작성을 하신 것 같네요.
몇 가지 눈에 띄는 수정사항을 알려드릴게요. 가능하면 말씀드리는 방향을 생각해 보시고 적용하시는게 나중에 변경사항이 생길 때 많은 도움이 될겁니다.
Retrofit을 생성하는 부분은 거의 모든 경우는 앱에 걸쳐서 한개의 인스턴스(Singleton)만 필요합니다. 네트웍작업을 리소스를 많이 소모하는 작업이므로 API를 호출할 때마다 생성한다면 낭비가 됩니다. 그리고 데이터를 공유하거나 하지 않기 때문에 따라서 해당 부분을 Singleton으로 생성하도록 수정해 보세요.
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://13.58.187.197:8080").build();
Retrofit과 마찬가지로 DBService 는 fetchCompanyinfo가 호출될 때마다 다시 생성할 필요가 없기 때문에, 외부에서 한번만 생성하도록 하세요.
DBService service = retrofit.create(DBService.class);
fetchCompanyinfo가 왜 ViewModel을 리턴하나요? 님이 리사이클러뷰 어댑터에 사용하실
데이터 타입이 와야할 것 같은데요. 만약 TabListViewModel가 그 클래스라면, 적합한 이름으로 꼭 바꾸세요.
안드로이드의 ViewModel을 연상시켜서, 코드를 상당히 읽기 헷갈리게 합니다.
이름을 님의 의도가 잘 드러나게 잘 짓는 것은 제일 어렵고도 첫번째로 많이 강조하는 좋은 코드의 필수조건입니다.
public class CompanyInfo {
private final int categoryIndex;
private final List<Company> companies;
//constructor, getter setter생략
}
public Single<CompanyInfo> fetchCompanyinfo(int categoryIndex){
return service.getCompanyinfo(categoryIndex)
.subscribeOn(Schedulers.io());
}
DBService 서비스를 호출하는 부분은 데이터를 처리하는 부분이므로 뷰인 Activity에 있을 필요가 없습니다.
Activity는 ViewModel에서 던져주는 데이터를 가지고 화면에 표시하기만 하면 됩니다. 따라서 아래코드는 ViewModel 을 통해 호출되어야 합니다. 실제 데이터의 호출은 UseCase가 백그라운드 쓰레드 안에 합니다. DbService는 UseCase에 필요한 의존성(Depedency)가 되고 외부에서 생성해서 넣어줍니다. 마찬가지로 ViewModel에도 외부에서 UseCase를 넣어줍니다.
public class SchedulerProvider {
public void io(): Schduer {
return Schedulers.io();
}
}
public FecthCompanyUseCase {
private final DbService dbService;
public FecthCompanyUseCase(DbService dbService, SchedulerProvider schedulers) {
this.dbService = dbService;
}
public fetchCompanyInfo(int categoryIndex): Single<CompanyInfo> {
// observeOn이 필요없는 이유는 LiveData.postValue는 백그라운드 쓰레드에서도 값을 전달할 수 있기 때문입니다.
// liveData.value 를 사용하신다면 메인쓰레드로 전환해야 겠죠.
return dbService.getCompanyinfo(categoryIndex)
.subscribeOn(schedulers.io());
}
}
public class HomeViewModel extends ViewModel {
private final FecthCompanyUseCase fetchCompanyUseCase;
private final MutableLiveData<CompanyInfo> companyInfoLiveData;
private Disposble disposable = null;
// onClear에서 RxJava에서 사용했던 리소스를 해제해주셔 합니다. 그래야 메모리 누수가 없어요.
@Override
public void onCleared() {
super.onCleared();
if( diposable != null )
disposable.dispose();
}
public LiveData<CompanyInfo> getCompanyInfoLiveData() {
return this.companyInfosData;
}
public HomeViewModel(FecthCompanyUseCase fetchCompanyUseCase) {
this.fetchCompanyUseCase = fetchCompanyUseCase
}
// observeOn이 필요없는 이유는 LiveData.postValue는 백그라운드 쓰레드에서도 값을 전달할 수 있기 때문입니다.
// liveData.value 를 사용하신다면 메인쓰레드로 전환해야 겠죠.
public void fetchCompanyinfo(int categoryIndex){
diposable = fetchCompanyUseCase
.fetchCompanyInfo(categoryIndex)
.subscribe(
v -> notifyCompanyInfos(v) ,
err -> System.err.println("onError() : err :" + err.getMessage()
}
private void notifyCompanyInfo(companyInfos: List<CompanyInfo>) {
companyInfoLiveData.postValue(companyInfos);
}
}
이제 View쪽에서 ViewModel에 있는 companyInfosLiveData를 observe하고 있다가, 값이 오면 그 때 리사이클러뷰를 갱신해주면 됩니다.
public class HomeFragment extends Fragment {
// 중복코드 생략
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
homeViewModel = ... // 이 부분을 기존 코드대로 사용할 수 없을 겁니다. ViewModelFactory를 통해 필요한 ViewModel에 필요한 의존 클래스들을 주입해주어야 합니다.
// 이부분은 출근관계로 시간이 없어서 생략합니다. 안드로이드 개발 문서에 샘플코드가 있으니 거기서 가져다 쓰세요.
//뷰 생성
// ViewModel 에서 변경된 데이터가 있는지 observing
final Observer<CompanyInfo> companyInfoObserver = new Observer<>() {
@Override
public void onChanged(@Nullable final CompanyInfo companyInfo) {
updateComanyInfo(companyInfos;
}
};
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.getCompanyInfoLiveData().companyInfoObserver(this.getViewLifecycleObserver(), companyInfObserver);
}
private void updateComanyInfo(CompanyInfo companyInfo){
//여기서 리사이클러뷰 갱신
}
}