Я работаю над проектом, в котором пытаюсь реализовать компоненты архитектуры Android с привязкой данных. У меня есть активность, модель просмотра и репозиторий, и я создаю страницу входа в систему прямо сейчас. Мне нужно сделать две функции репозитория, чтобы пользователь мог войти в систему, первая функция вернет uid, а, передав этот uid, вторая функция вернет детали. как только все будет сделано, я хочу только перенаправить пользователя на внутреннюю страницу. Я пробовал использовать Transformations.switchMap, который не работает. Пожалуйста помоги...
public class LoginViewModel extends ViewModel {
private final VendorRepository vendorRepository;
private final ResourceProvider resourceProvider;
public MutableLiveData<String> error = new MutableLiveData<>();
public MutableLiveData<Boolean> loading = new MutableLiveData<>();
private MutableLiveData<Resource<String>> vendorId = new MutableLiveData<>();
public LiveData<Resource<Vendor>> vendor;
public LoginViewModel() {
this.vendorRepository = VendorRepository.getInstance();
this.resourceProvider = ResourceProvider.getInstance();
/*vendor = Transformations.switchMap(vendorId, new Function<Resource<String>, LiveData<Resource<Vendor>>>() {
@Override
public LiveData<Resource<Vendor>> apply(Resource<String> input) {
if (input!=null&&input.status.equals(Status.SUCCESS))
return vendorRepository.getVendor(vendorId.getValue().data);
else return null;
}
});*/
}
/**
* called when a user clicks on the login button
* if the inputs are valid, will call the login function
*
* @param email entered email
* @param password entered password
*/
public void onClickLogin(String email, String password) {
//loading.setValue(true);
if (validInputs(email, password)) {
vendorId = vendorRepository.login(
email, password
);
} else loading.setValue(false);
}}
Это моя модель просмотра
public class VendorRepository {
private static VendorRepository INSTANCE;
private FirebaseAuth firebaseAuth;
private FirebaseFirestore firebaseFirestore;
public static VendorRepository getInstance() {
if (INSTANCE == null)
INSTANCE = new VendorRepository();
return INSTANCE;
}
private VendorRepository() {
this.firebaseAuth = FirebaseAuth.getInstance();
this.firebaseFirestore = FirebaseFirestore.getInstance();
}
public MutableLiveData<Resource<String>> login(String email, String password) {
final MutableLiveData<Resource<String>> data = new MutableLiveData<>();
data.setValue(Resource.<String>loading(null));
firebaseAuth
.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
data.postValue(Resource.success(task.getResult().getUser().getUid()));
} else {
data.postValue(Resource.<String>error(task.getException().getMessage(), null));
}
}
});
return data;
}
public LiveData<Resource<Vendor>> getVendor(String id) {
final MutableLiveData<Resource<Vendor>> data = new MutableLiveData<>();
data.postValue(Resource.<Vendor>loading(null));
firebaseFirestore
.collection(DB_VENDOR)
.document(id)
.get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
Vendor vendor = task.getResult().toObject(Vendor.class);
data.postValue(Resource.success(vendor));
} else {
data.postValue(Resource.<Vendor>error(task.getException().getMessage(), null));
}
}
});
return data;
} }
Это мое репо
все мои функции репозитория работают нормально, но данные моего идентификатора поставщика в реальном времени не запускаются, даже если я наблюдаю это в своей деятельности. Я хочу наблюдать за vendorId в модели просмотра и на основании этого хочу вызвать getVendor (id)
Проверьте наличие значения NULL для vendorId после вызова vendorId = vendorRepository.login. Кроме того, проверьте интерфейс OnCompleteListener, чтобы увидеть, не пропущены ли вам какие-либо другие методы обратного вызова. Наконец, поместите журнал (что-то вроде Log.d("myclass", "inside method..."); во все методы обратного вызова, которые вы реализуете в OnCompleteListener внутри метода login. Вы также можете в другом потоке продолжать спать в течение нескольких мс и после каждого пробуждения проверять, является ли vendorId.getValuenull или нет .
vendorId не равен нулю, и я получаю идентификатор в обратном вызове oncomplete .. но мои данные vendorId в реальном времени в viewmodel не запускаются
Какого наблюдателя вы прикрепили к идентификатору поставщика Livedata? Я не вижу прикрепленных сюда наблюдателей. Вы прикрепили его к какому-либо другому классу (вероятно, к вашему классу деятельности), который вы, очевидно, не вставляли здесь? Или вы его совсем не прикрепили?
Могу ли я использовать switchMap для наблюдения за vendorId и вызвать getVendor () на основе изменений в vendorId
Можно, но не обязательно. Вы можете вызвать VendorRepository.getInstance().getVendor( vendorId) в самом обозревателе живых данных vendorId.
Я не вижу, что вам нужны живые данные, которые представляют собой преобразованный вывод данных vendorId Live. Вы, вероятно, можете вставить код, вызывающий вызов репозитория getVendor, в экземпляр Function<String, Livedata<Vendor>, но я не вижу в этом необходимости.
где я напишу код для этого наблюдателя, я не хочу писать его в действии, как наблюдать идентификатор поставщика в модели просмотра
Вам как бы придется записать его в activity. В противном случае вам придется передавать ссылку this на действие, где бы вы ни создавали наблюдателя. Поверьте, вам не нужно беспокоиться об утечке памяти, создав анонимный класс для наблюдателя в действии. Как разработаны модели ViewModels, наблюдатель будет отсоединен и впоследствии уничтожен, как только активность будет уничтожена. Вы можете прочитать об этом в руководстве для разработчиков Android на ViewModels и LiveData.
могу ли я наблюдать за MutableLiveData в действии
Да, он вроде как создан для этой цели. Напишу ответ на этот вопрос.
спасибо за терпение, в любом случае это не работает для меня
Проверьте ответ.
Вам необходимо добавить observer из живых данных vendorId где-нибудь в вашем activity, возможно, в onCreate(Bundle) после того, как вы инициализировали viewModel.
Ваш код будет выглядеть примерно так.
public final class MyActivity extends AppCompatActivity {
...
LoginViewModel mViewModel;
@Override protected final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
mViewModel = ViewModelProviders.of(this)
.get(LoginViewModel.class);
//make vendorId public in the viewModel
mViewModel.vendorId.observe ( this, new Observer<String> (){
@Override public void onChanged(@Nullable final String vendorId) {
VendorRepository.getInstance().getVendor(vendorId);
}
});
//Similarly, add observer for the vendor live data
}
}
Какую ошибку вы получаете? Есть проблема в исполнении
getVendorилиlogin? Можете ли вы вставить трассировку стека в вопрос?