Java 访问片段时偶尔出现NPE';s观点
当输入片段时,我偶尔会得到Java 访问片段时偶尔出现NPE';s观点,java,android,android-fragments,android-view,android-lifecycle,Java,Android,Android Fragments,Android View,Android Lifecycle,当输入片段时,我偶尔会得到NullPointerException。它发生在应用程序在后台很长一段时间,然后我打开它并滑动到这个片段 public class SummaryFragment extends Fragment implements FragmentLifecycle { private static final String TAG = "DTAG"; private DateFormat dateFormatName; private Preferen
NullPointerException
。它发生在应用程序在后台很长一段时间,然后我打开它并滑动到这个片段
public class SummaryFragment extends Fragment implements FragmentLifecycle {
private static final String TAG = "DTAG";
private DateFormat dateFormatName;
private Preference prefs;
private List<String> monthList;
private TextView totalTimeFullTv;
private TextView totalTimeNetTv;
private TextView averageTimeTv;
private TextView overUnderTv;
private TextView minTimeTv;
private TextView maxTimeTv;
private TextView vacationsTv;
private TextView sickTv;
private TextView headlineTv;
private TextView overUnderTvH;
private OnFragmentInteractionListener mListener;
public SummaryFragment() {
// Required empty public constructor
}
public static SummaryFragment newInstance(String param1, String param2) {
SummaryFragment fragment = new SummaryFragment();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View RootView = inflater.inflate(R.layout.fragment_summary, container, false);
dateFormatName = new SimpleDateFormat(getResources().getString(R.string.month_text));
monthList = Arrays.asList(new DateFormatSymbols().getMonths());
prefs = new Preference(GeneralAdapter.getContext());
totalTimeFullTv = RootView.findViewById(R.id.textView_sum_ttf);
totalTimeNetTv = RootView.findViewById(R.id.textView_sum_ttn);
averageTimeTv = RootView.findViewById(R.id.textView_sum_av);
overUnderTv = RootView.findViewById(R.id.textView_sum_ou);
overUnderTvH = RootView.findViewById(R.id.textView_sum_ou_h);
minTimeTv = RootView.findViewById(R.id.textView_sum_min);
maxTimeTv = RootView.findViewById(R.id.textView_sum_max);
vacationsTv = RootView.findViewById(R.id.textView_sum_vac);
sickTv = RootView.findViewById(R.id.textView_sum_sick);
headlineTv= RootView.findViewById(R.id.textView_sum_headline);
return RootView;
}
private void refreshData() {
if (prefs == null)
{
prefs = new Preference(GeneralAdapter.getContext());
}
String month = prefs.getString(Preference.CURRENT_MONTH);
MonthData monthData = Calculators.CalculateLocalData(MainActivity.db.getAllDays(month));
totalTimeFullTv.setText(monthData.getTotalTimeFull()); //Crash here
totalTimeNetTv.setText(monthData.getTotalTimeNet());
averageTimeTv.setText(monthData.getAverageTime());
overUnderTv.setText(monthData.getOverUnder());
if (monthData.getOverUnderFloat()<0)
{
overUnderTvH.setText(R.string.sum_over_time_neg);
overUnderTv.setTextColor(ContextCompat.getColor(GeneralAdapter.getContext(),R.color.negative_color));
}
else
{
overUnderTvH.setText(R.string.sum_over_time_pos);
overUnderTv.setTextColor(ContextCompat.getColor(GeneralAdapter.getContext(),R.color.positive_color));
}
minTimeTv.setText(monthData.getMinTime());
maxTimeTv.setText(monthData.getMaxTime());
vacationsTv.setText(""+monthData.getVacations());
sickTv.setText(""+monthData.getSick());
headlineTv.setText(month);
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttachFragment(Fragment childFragment) {
super.onAttachFragment(childFragment);
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void onPauseFragment() {
}
@Override
public void onResumeFragment()
{
refreshData();
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
日志:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
int currentPosition = 0;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
FragmentLifecycle fragmentToHide = (FragmentLifecycle) adapter.getItem(currentPosition);
fragmentToHide.onPauseFragment();
FragmentLifecycle fragmentToShow = (FragmentLifecycle) adapter.getItem(position);
fragmentToShow.onResumeFragment(); //Crash start
currentPosition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
E/AndroidRuntime: FATAL EXCEPTION: main
Process: michlind.com.workcalendar, PID: 25038
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at michlind.com.workcalendar.mainfragments.SummaryFragment.refreshData(SummaryFragment.java:99)
at michlind.com.workcalendar.mainfragments.SummaryFragment.onResumeFragment(SummaryFragment.java:147)
at michlind.com.workcalendar.activities.MainActivity.onPageSelected(MainActivity.java:84)
at android.support.v4.view.ViewPager.dispatchOnPageSelected(ViewPager.java:1941)
at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:680)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:664)
at android.support.v4.view.ViewPager.onTouchEvent(ViewPager.java:2257)
at android.view.View.dispatchTouchEvent(View.java:11776)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2962)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2643)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:448)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1829)
at android.app.Activity.dispatchTouchEvent(Activity.java:3307)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:410)
at android.view.View.dispatchPointerEvent(View.java:12015)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4795)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4609)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4200)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4166)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4293)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4174)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4350)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4200)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4166)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4174)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6661)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6635)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6596)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6764)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:186)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:325)
at android.os.Looper.loop(Looper.java:142)
at android.app.ActivityThread.main(ActivityThread.java:6494)
更新:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
int currentPosition = 0;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
FragmentLifecycle fragmentToHide = (FragmentLifecycle) adapter.getItem(currentPosition);
fragmentToHide.onPauseFragment();
FragmentLifecycle fragmentToShow = (FragmentLifecycle) adapter.getItem(position);
fragmentToShow.onResumeFragment(); //Crash start
currentPosition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
E/AndroidRuntime: FATAL EXCEPTION: main
Process: michlind.com.workcalendar, PID: 25038
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at michlind.com.workcalendar.mainfragments.SummaryFragment.refreshData(SummaryFragment.java:99)
at michlind.com.workcalendar.mainfragments.SummaryFragment.onResumeFragment(SummaryFragment.java:147)
at michlind.com.workcalendar.activities.MainActivity.onPageSelected(MainActivity.java:84)
at android.support.v4.view.ViewPager.dispatchOnPageSelected(ViewPager.java:1941)
at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:680)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:664)
at android.support.v4.view.ViewPager.onTouchEvent(ViewPager.java:2257)
at android.view.View.dispatchTouchEvent(View.java:11776)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2962)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2643)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2968)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:448)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1829)
at android.app.Activity.dispatchTouchEvent(Activity.java:3307)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:68)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:410)
at android.view.View.dispatchPointerEvent(View.java:12015)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4795)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4609)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4200)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4166)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4293)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4174)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4350)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4200)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4166)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4174)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4147)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6661)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6635)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6596)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6764)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:186)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:325)
at android.os.Looper.loop(Looper.java:142)
at android.app.ActivityThread.main(ActivityThread.java:6494)
我最终使用了:
@Override
public void onPageSelected(int position) {
Fragment fragment = adapter.getFragment(position);
if (fragment != null) {
fragment.onResume();
}
}
在MainActivity中,并在每个片段中使用onResume()。此解决方案适用于适配器:
在创建此片段的所有视图之前,将调用onResumeFragment()。
首先尝试重新创建新实例,然后在活动中调用FragmentLifeCycle
接口的onResumeFragment
您应该在onCreateView
中膨胀布局,但不应该使用onCreateView
中的findViewById
初始化其他视图
下面是来自FragmentManager的代码
// This calls onCreateView()
f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState);
// Null check avoids possible NPEs in onViewCreated
// It's also safe to call getView() during or after onViewCreated()
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
最好在onViewCreated
中为字段指定子视图。这是因为框架为您自动执行空检查,以确保片段的视图层次结构已正确创建和膨胀(如果使用XML布局文件)
创建视图后,初始化视图。问题是,您试图过早访问视图:此时尚未创建视图层次结构 如果您发布了将在下一帧上发生的事件,则可以保证已设置视图层次结构:
@Override
public void onResumeFragment() {
new Handler().post(new Runnable() {
@Override
public void run() {
refreshData();
}
});
}
ViewPager
将两侧的多个项目连接在一起(即碎片恢复),但是FragmentPagerAdapter
使用Fragment.setUserVisibleHint
指示哪个项目是当前项目。相反,利用这一点
以下是如何利用用户可见提示:
FragmentLifecycle
界面FragmentPagerAdapter.getItem
是一种工厂方法。它总是应该返回一个片段的新实例。如果您试图缓存它们,请删除缓存(1),不要使用getItem
yourself(2)
onPageSelected
后将被垃圾收集您正在错误地使用OnPageChangeListener。这不是控制视图生命周期事件的安全方法。您需要将PagerAdapter与ViewPager结合使用,并覆盖其实例化Item/destroyItem回调 请参见此示例: PagerAdapter对ViewPager的作用就像ListAdapter对ListView的作用一样,要使系统正常工作,您需要两者 使用
onViewCreated()
fragment的回调方法来更新数据,这样您就可以确保所有视图的布局都是完美的
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
refreshData();
}
使用
处理程序仍然有风险,因为您无法确定视图是否膨胀。问题
片段的生命周期是独立的。您无法确定当注册onPageSelected()
时,该片段是否已被放置。这是一个异步事件。所以你不能依赖这个回调
但另一方面,您也不能仅依赖于onResume()
,因为在ViewPager中,与当前可见页面相邻的页面是预加载的
解决方案
当片段对用户可见并正在运行时,主要需要refreshData()
。该词的定义也是如此:
当片段对用户可见并正在运行时调用。(……)
因此,只需在片段的onResume()
中调用refreshData()
,如果您注意到在ViewPager未真正显示此页面时调用了此函数,请不要担心。添加此签入refreshData()方法:
正如大多数人所说,您需要确保您的片段是活动的,并且对用户可见。我也有类似的问题。我使用onHiddenChanged来决定何时重新加载数据
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (!hidden) {
refreshData();
}
}
当我为ViewPager实现自定义生命周期时,我也遇到了同样的问题。我认为您正在使用FragmentStatePagerAdapter使用ViewPager填充片段。正如我们所知,碎片状态页面雷达在碎片失去焦点时会摧毁所有碎片。我们需要使用单例模式为每个页面提供相同的对象
在您的代码中,对于单例模式,片段创建可以如下所示
private SummaryFragment mInstance;
private SummaryFragment() {
// Required empty public constructor
}
public static SummaryFragment newInstance(String param1, String param2) {
if(mInstance == null)
mInstance = new SummaryFragment();
return mInstance;
}
这样做解决了我的问题。如果这不适合你?你能分享你的PagerAdapter课程吗。你为什么不把totalTimeFullTv
选为TextView@vm345如果OP使用appcompat,则不需要强制转换。appcompat将Android更高版本中的一个新更新修改为片段和活动,这使得在使用appcompat导入时强制转换变得多余。您是否尝试在onResumeFragment()中延迟50-100毫秒?尝试了10次,效果似乎好多了,但仍有几次崩溃。不要试着用500!但这似乎不是正确的解决方案。这只是一个解决方法。您需要将refreshData()
放在onActivityCreated()
方法中,以避免这种情况。您的视图没有被创建。它大大减少了崩溃,但它们仍然偶尔发生……有时仍然发生。目前正在尝试500毫秒!但这似乎不是正确的编码解决方案。在我的日志中,我可以肯定地看到OnCreate发生在onResumeFragment之前。OnCreate中的视图不为null。这很奇怪。这不是推荐的解决方案。这基本上是希望页面是在设定的毫秒数之后布局的。在某些情况下,这种延迟可能“太早”,