当我回到片段时,观察者会立即被调用
When I go back to a Fragment the observer is immediately called
我有一个观察者比当它被称为变化片段。
问题是当我返回时立即调用观察者并且我的应用程序崩溃并显示
java.lang.IllegalArgumentException: navigation destination
com.superapps.ricardo.tablepro:id/action_searchFragment_to_yourGameList2
is unknown to this NavController.
我不明白为什么叫它。
这是更改列表的唯一方法
override fun onSuccess(gamePair: Pair<Int, List<BggGame>>) {
CoroutineScope(Main).launch{
//goToList(gamePair.second, binding.input.text.toString())
viewModel.setGameList(gamePair.second)
}
}
这是视图模型创建和更改片段代码
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(SearchViewModel::class.java)
viewModel.gameList.observe(viewLifecycleOwner, Observer {
goToList(it, binding.input.text.toString())
})
}
private fun goToList(games: List<BggGame>, user: String) {
val action = SearchFragmentDirections.actionSearchFragmentToYourGameList2(user)
val gameList = GameList()
gameList.gameList = games
action.gameList = gameList
try {
Navigation.findNavController(view!!).navigate(action)
viewModel.gameList.removeObservers(viewLifecycleOwner)
} catch (e: Exception){
Log.e("a0,","a..", e)
}
progressDialog.dismiss()
}
LiveData
保留最后设置的值。在 LivaData
上调用 observe()
时,如果 LiveData
有值,则立即使用先前设置的值调用观察者。
如果您想像您的用例一样将 LiveData
用于 "events",您的实时数据应该公开一个只能使用一次的 Event
对象。
这是一个很好的例子 implementation 这样的 Event
class.
来自文章:
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
ViewModel 中的用法:
val gameList = MutableLiveData<Event<List<BggGame>>()
fun setGameList(gameList: List<BggGame>) {
gameList.value = Event(gameList)
}
视图中的用法:
viewModel.gameList.observe(this, Observer {
it.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
goToList(it, binding.input.text.toString())
}
})
在您的 viewModel
中使用 SingleLiveEvent
而不是 MutableLiveData
或 LiveData
。
这是 SingleLiveEvent
class ,您可以在 util
包中使用它:
import android.util.Log;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import java.util.concurrent.atomic.AtomicBoolean;
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private static final String TAG = "SingleLiveEvent";
private final AtomicBoolean mPending = new AtomicBoolean(false);
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
}
// Observe the internal MutableLiveData
super.observe(owner, new Observer<T>() {
@Override
public void onChanged(@Nullable T t) {
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t);
}
}
});
}
@MainThread
public void setValue(@Nullable T t) {
mPending.set(true);
super.setValue(t);
}
}
我有一个观察者比当它被称为变化片段。
问题是当我返回时立即调用观察者并且我的应用程序崩溃并显示
java.lang.IllegalArgumentException: navigation destination com.superapps.ricardo.tablepro:id/action_searchFragment_to_yourGameList2 is unknown to this NavController.
我不明白为什么叫它。
这是更改列表的唯一方法
override fun onSuccess(gamePair: Pair<Int, List<BggGame>>) {
CoroutineScope(Main).launch{
//goToList(gamePair.second, binding.input.text.toString())
viewModel.setGameList(gamePair.second)
}
}
这是视图模型创建和更改片段代码
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(SearchViewModel::class.java)
viewModel.gameList.observe(viewLifecycleOwner, Observer {
goToList(it, binding.input.text.toString())
})
}
private fun goToList(games: List<BggGame>, user: String) {
val action = SearchFragmentDirections.actionSearchFragmentToYourGameList2(user)
val gameList = GameList()
gameList.gameList = games
action.gameList = gameList
try {
Navigation.findNavController(view!!).navigate(action)
viewModel.gameList.removeObservers(viewLifecycleOwner)
} catch (e: Exception){
Log.e("a0,","a..", e)
}
progressDialog.dismiss()
}
LiveData
保留最后设置的值。在 LivaData
上调用 observe()
时,如果 LiveData
有值,则立即使用先前设置的值调用观察者。
如果您想像您的用例一样将 LiveData
用于 "events",您的实时数据应该公开一个只能使用一次的 Event
对象。
这是一个很好的例子 implementation 这样的 Event
class.
来自文章:
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
ViewModel 中的用法:
val gameList = MutableLiveData<Event<List<BggGame>>()
fun setGameList(gameList: List<BggGame>) {
gameList.value = Event(gameList)
}
视图中的用法:
viewModel.gameList.observe(this, Observer {
it.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
goToList(it, binding.input.text.toString())
}
})
在您的 viewModel
中使用 SingleLiveEvent
而不是 MutableLiveData
或 LiveData
。
这是 SingleLiveEvent
class ,您可以在 util
包中使用它:
import android.util.Log;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import java.util.concurrent.atomic.AtomicBoolean;
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private static final String TAG = "SingleLiveEvent";
private final AtomicBoolean mPending = new AtomicBoolean(false);
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
}
// Observe the internal MutableLiveData
super.observe(owner, new Observer<T>() {
@Override
public void onChanged(@Nullable T t) {
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t);
}
}
});
}
@MainThread
public void setValue(@Nullable T t) {
mPending.set(true);
super.setValue(t);
}
}