我的MainActivity中有一个带有viewpager的布局。
我的PagerAdapter
如下:
public class MainActivityPagerAdapter extends PagerAdapter {
public MainActivityPagerAdapter(FragmentManager fm, int numOfTabs) {
super(fm, numOfTabs);
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new StoresFragment();
case 1:
return new OrdersFragment();
default:
return null;
}
}
}
我正从另一个这样的活动回来:
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish(); //finishAffinity();
但是随后我在MainActivity的viewpager中的一个片段中得到了java.lang.IllegalStateException
。
我阅读了许多相关问题,并试图解决此问题。有人说,这是在PagerAdapter之外保留对Fragments的引用时发生的。但是,正如您在我的代码中看到的那样,我没有这样做。
有人知道我在做什么错吗?
编辑-Stacktrace
FATAL EXCEPTION: main
Process: com.lifo.skipandgo, PID: 23665
java.lang.IllegalStateException: Fragment OrdersFragment{42c2a740} not attached to a context.
at android.support.v4.app.Fragment.requireContext(Fragment.java:614)
at android.support.v4.app.Fragment.getResources(Fragment.java:678)
at com.lifo.skipandgo.activities.fragments.OrdersFragment$1.results(OrdersFragment.java:111)
at com.lifo.skipandgo.connectors.firestore.QueryResult.receivedResult(QueryResult.java:37)
at com.lifo.skipandgo.controllers.UserController$2.onUpdate(UserController.java:88)
at com.lifo.skipandgo.connectors.firestore.QuerySubscription.onEvent(QuerySubscription.java:59)
at com.lifo.skipandgo.connectors.firestore.QuerySubscription.onEvent(QuerySubscription.java:18)
at com.google.firebase.firestore.zzg.onEvent(Unknown Source)
at com.google.firebase.firestore.g.zzh.zza(SourceFile:28)
at com.google.firebase.firestore.g.zzi.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5653)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
at dalvik.system.NativeStart.main(Native Method)
编辑: 有趣的是,发生错误时,视图已正确加载。因为该错误会在片段再次显示后约10-15秒后发生。我在我的orderFragment中发生错误:
orders = new QueryResult<UserOrder>(UserOrder.class) {
@Override
public void results(List<UserOrder> results) {
orderLoadingMessage.setBackgroundColor(getResources().getColor(R.color.green));
}
}
我在onCreateView
中执行此操作,结果在加载视图后约10-15秒出现。
答案 0 :(得分:1)
问题似乎是,您的片段正在侦听某些事件(通过UserController和QueryResult),并且在将片段附加到上下文之前触发了这些事件。
当片段分离时尝试注销该片段,并在附加后再次对其重新注册(LiveData也可以帮助解决此问题)。另一种方法是在分离时接收和存储事件,并仅在附加后才处理。
答案 1 :(得分:0)
将片段与活动分离后,将触发某些回调。要解决此问题,您需要在执行任何回调之前检查是否已添加片段。例如,将orders
对象的初始化更改为此:
orders = new QueryResult<UserOrder>(UserOrder.class) {
@Override
public void results(List<UserOrder> results) {
if(isAdded()) {
orderLoadingMessage.setBackgroundColor(
getResources().getColor(R.color.green));
}
}
}
答案 2 :(得分:0)
在我的情况下,当我显示DialogFragment
并调用它的方法时,发生了此异常。由于片段在调用方法之前尚未附加到FragmentManager
(此操作异步完成),因此应用程序崩溃了。
val fragment = YourDialogFragment.newInstance()
fragment.show(fragmentManager, YourDialogFragment.TAG)
// This will throw an exception.
fragment.setCaptions("Yes", "No")
如果您将片段添加为FragmentManager
,则会得到另一个exception:java.lang.IllegalArgumentException: No view found for id 0x1020002 (android:id/content) for fragment
(或者类似的,如果您使用另一个id)。
您可以通过post
(或postDelayed
)调用片段方法,但这是一个不好的解决方案:
view?.post {
fragment.setCaptions("Yes", "No")
}
当前我使用childFragmentManager
而不是fragmentManager
:
val fragment = YourDialogFragment.newInstance()
fragment.show(childFragmentManager, YourDialogFragment.TAG)
fragment.setCaptions("Yes", "No")
我不记得自己做了什么,但是现在可以了。
答案 3 :(得分:0)
viewPager.offscreenPageLimit = (total number of fragments - 1)
viewPager.adapter = Adapter
如果您使用的是Viewpager,请使用此 如果您使用的是底部导航,只需检查if(context!= null)
答案 4 :(得分:0)
我有类似的问题。我已经按照Ferini的建议解决了。我使用的是实时数据,该数据在附加上下文之前就已触发。
这是我的完整实现方式
public class PurchaseOrderFragment extends Fragment {
FragmentPurchaseOrderBinding binding;
CurrentDenominationViewModel currentDenominationViewModel;
@Inject
ViewModelFactory viewModelFactory;
CurrentVoucherChangedObserver observer;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
currentDenominationViewModel = new ViewModelProvider(requireActivity(),viewModelFactory).get(CurrentDenominationViewModel.class);
observer = new CurrentVoucherChangedObserver();
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_purchase_order, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
currentDenominationViewModel.getCurrentVoucherStatisticsLiveData().observe(requireActivity(), observer);
}
@Override
public void onAttach(@NonNull Context context) {
AndroidSupportInjection.inject(this);
super.onAttach(context);
}
@Override
public void onDetach() {
super.onDetach();
currentDenominationViewModel.getCurrentVoucherStatisticsLiveData().removeObserver(observer);
}
final class CurrentVoucherChangedObserver implements Observer<VoucherStatistics> {
@Override
public void onChanged(VoucherStatistics x) {
String denomination = x.getDenomination()+"";
binding.tvDenomination.setText(denomination);
String stockAmount = requireContext().getResources().getString(R.string.StockAmount);
String text= "("+String.format(stockAmount,x.getQuantity()+"")+")";
binding.tvInStock.setText(text);
}
}
}
答案 5 :(得分:0)
在更新Activity UI之前使用它:
if(isAdded())// This {@link androidx.fragment.app.Fragment} class method is responsible to check if the your view is attached to the Activity or not
{
// TODO Update your UI here
}
答案 6 :(得分:-1)
您的解决方案
将您的getItem()方法更改为
switch (position) {
case 0:
return new StoresFragment();
case 1:
return new OrdersFragment();
default:
return null;
}