简体   繁体   English

ViewPager的OnPageChangeListener的onPageSelected方法上的片段崩溃

[英]Fragment Crashes on ViewPager's OnPageChangeListener's onPageSelected method

I met a strange thing with ViewPager. 我在ViewPager上遇到了一件奇怪的事情。 I googled but do not find anything useful. 我用谷歌搜索,但找不到任何有用的东西。
So I post what I have met here, maybe later someone get the same problem, or maybe luckily some genius guys can solve it. 因此,我在这里发布了我遇到的问题,也许以后有人遇到同样的问题,或者幸运的是,有些天才的家伙可以解决它。
The situation shows as following: 情况如下:
There are two page in the demo application. 演示应用程序中有两个页面。

  1. HomeActivity is the main page, and there is a viewpager in it. 主页活动是主页,并且其中有一个viewpager。 The viewpager have five fragments(Class PlusOneFragment) in it. viewpager中有五个片段(Class PlusOneFragment)。 In the fagment, there are two textviews. 在fag中,有两个textview。 In the onCreateView method we assign one TextView to mValueTv field. 在onCreateView方法中,我们将一个TextView分配给mValueTv字段。
  2. AboutActivity is the other page used to trigger a application crash. AboutActivity是用于触发应用程序崩溃的另一个页面。 Beacause I have used UncaughtExceptionHandler to catch exception in a custom Application class, which inherit from android.app.Application . 因为我已经使用UncaughtExceptionHandler在自定义Application类中捕获异常,该类继承自android.app.Application So then application will goto the HomeActivity. 因此,应用程序将转到HomeActivity。

But when crashing, Then something sucks. 但是当崩溃时,然后会有些糟透了。 The applcation crashes again. 应用再次崩溃。
That really bugged me. 那真让我烦恼。
In the HomeActivity, the viewpager has a ViewPager.OnPageChangeListener. 在HomeActivity中,viewpager具有ViewPager.OnPageChangeListener。
When its page changed, a methond of the specific position's fragment will be invoked in the onPageSelected method. 当其页面更改时,将在onPageSelected方法中调用特定位置片段的方法。
The method will set fragment mValueTv's value. 该方法将设置片段mValueTv的值。 In normal situation, it works fine, but when it comes to crash, the method throws a java.lang.NullPointerException exception. 在正常情况下,它可以正常工作,但是当崩溃时,该方法将引发java.lang.NullPointerException异常。

05-06 21:37:24.392  17120-17120/com.rxread.viewpagerissue E/MessageQueue-JNI﹕ java.lang.NullPointerException
        at com.rxread.viewpagerissue.PlusOneFragment.onPageSeleted(PlusOneFragment.java:49)
        at com.rxread.viewpagerissue.HomeActivity$1.onPageSelected(HomeActivity.java:33)
        at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:571)
        at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:555)
        at android.support.v4.view.ViewPager.onTouchEvent(ViewPager.java:2022)
        at android.view.View.dispatchTouchEvent(View.java:7725)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2212)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1945)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2218)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2218)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2218)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2218)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2218)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2218)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2242)
        at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1536)
        at android.app.Activity.dispatchTouchEvent(Activity.java:2458)
        at android.support.v7.internal.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:59)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2190)
        at android.view.View.dispatchPointerEvent(View.java:7905)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4009)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3888)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3499)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3468)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3575)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3476)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3632)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3499)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3468)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3476)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5657)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5637)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5608)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5815)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:138)
        at android.os.Looper.loop(Looper.java:123)
        at android.app.ActivityThread.main(ActivityThread.java:5081)
        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:878)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
        at dalvik.system.NativeStart.main(Native Method)

Because there were too much code, so I packed them. 因为代码太多,所以我打包了它们。 The demo link is . 演示链接为
I really hope someone can help me. 我真的希望有人能帮助我。 Thanks very much. 非常感谢。


HomeActivity 家庭活动

public class HomeActivity extends ActionBarActivity {
ViewPager mViewpager;
BaseTabHostPagerAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    mViewpager= (ViewPager) this.findViewById(R.id.home_ivp);
    mViewpager.setOnPageChangeListener(new ViewPager.OnPageChangeListener(){

        @Override
        public void onPageScrolled(int i, float v, int i1) {

        }

        @Override
        public void onPageSelected(int i) {
            Object object=mAdapter.getItem(i);
            if(object instanceof PlusOneFragment){
                ((PlusOneFragment)object).onPageSeleted(i);
            }
        }

        @Override
        public void onPageScrollStateChanged(int i) {

        }
    });

    mAdapter=new BaseTabHostPagerAdapter(getSupportFragmentManager());
    mViewpager.setAdapter(mAdapter);
    mAdapter.addPager("new 1", PlusOneFragment.newInstance("new 1"));
    mAdapter.addPager("new 2",PlusOneFragment.newInstance("new 2"));
    mAdapter.addPager("new 3",PlusOneFragment.newInstance("new 3"));
    mAdapter.addPager("new 4", PlusOneFragment.newInstance("new 4"));
    mAdapter.addPager("new 5", PlusOneFragment.newInstance("new 5"));
    mAdapter.notifyDataSetChanged();

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_home, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        AboutActivity.actionTo(this);
        return true;
    }

    return super.onOptionsItemSelected(item);
}

} }


AboutActivity 关于活动

public class AboutActivity extends ActionBarActivity {

public static void actionTo(Context context){
    Intent intent=new Intent(context,AboutActivity.class);
    context.startActivity(intent);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_about);

    TextView mClickToCrash= (TextView) findViewById(R.id.about_to_crash_tv);
    mClickToCrash.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int exception=2-2;
            int a=3/exception;
            Toast.makeText(AboutActivity.this, "GO EXCEPTION" + a, Toast.LENGTH_SHORT).show();
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_about, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

PlusOneFragment 加一个片段

public class PlusOneFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";

private String mParam1;
private TextView mValueTv;

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @return A new instance of fragment PlusOneFragment.
 */
// TODO: Rename and change types and number of parameters
public static PlusOneFragment newInstance(String name) {
    PlusOneFragment fragment = new PlusOneFragment();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, name);
    fragment.setArguments(args);
    return fragment;
}

public PlusOneFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
    }
}

public void onPageSeleted(int position){
    mValueTv.setText("onPageSeleted-Value:" +position+"--"+ SystemClock.currentThreadTimeMillis());
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_plus_one, container, false);
    TextView textView= (TextView) view.findViewById(R.id.fragment_name);
    textView.setText(mParam1);
    mValueTv= (TextView) view.findViewById(R.id.fragment_value);
    textView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mValueTv.setText("Value:"+ SystemClock.currentThreadTimeMillis());
            Toast.makeText(v.getContext(),"Toast",Toast.LENGTH_SHORT).show();
        }
    });
    return view;
}

@Override
public void onResume() {
    super.onResume();
}

ViewPagerIssueApplication ViewPagerIssueApplication

public class ViewPagerIssueApplication extends Application{
@Override
public void onCreate() {
    super.onCreate();
    CrashHandler handler = CrashHandler.getInstance();
    handler.init(getApplicationContext());
    Thread.setDefaultUncaughtExceptionHandler(handler);
}

} }


CrashHandler 崩溃处理程序

public class CrashHandler implements UncaughtExceptionHandler {
private static CrashHandler myCrashHandler;
private Context mContext;

private CrashHandler() {

}

public static synchronized CrashHandler getInstance() {
    if (myCrashHandler != null) {
        return myCrashHandler;
    } else {
        myCrashHandler = new CrashHandler();
        return myCrashHandler;
    }
}

public void init(Context context) {
    mContext = context;
}

@Override
public void uncaughtException(Thread arg0, Throwable exception) {
    StringWriter stackTrace = new StringWriter();
    exception.printStackTrace(new PrintWriter(stackTrace));
    System.err.println(stackTrace);
    System.exit(1);
}

} }


BaseTabHostPagerAdapter BaseTabHostPagerAdapter

public class BaseTabHostPagerAdapter extends FragmentPagerAdapter {

private List<String> names = new ArrayList<String>();
private List<Fragment> fragments = new ArrayList<Fragment>();

public BaseTabHostPagerAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int position) {

    if(position > fragments.size()){
        return null;
    }
    return fragments.get(position);
}

public List<Fragment> getFragmentsList(){
    return fragments;
}

@Override
public int getCount() {
    return fragments.size();
}

@Override
public CharSequence getPageTitle(int position) {

    if(position > names.size()){
        return null;
    }
    return names.get(position);
}

public void addPager(String tabStr,Fragment fragment) {

    if (fragment != null) {
        fragments.add(fragment);
        names.add(tabStr);
    }
}

public void setTab(int location, String tab){

    if(location<0||location>names.size()){
        return;
    }
    if(null!=tab){
        names.remove(location);
        names.add(location, tab);
    }
}

} }


Finally, with my team leader's help, I found that some fragments were not attached to the HomeActivity When crashing back to HomeActivity. 最后,在团队负责人的帮助下,当崩溃返回HomeActivity时,我发现某些片段未附加到HomeActivity。
The onPageSelected method is invoked ahead of onCreateView method. 在onCreateView方法之前调用onPageSelected方法。
The solution is doing getActivity null check in PlusOneFragment's onPageSeleted method. 解决方案是在PlusOneFragment的onPageSeleted方法中执行getActivity null检查。

    public void onPageSeleted(int position) {
    if (getActivity() == null) {
        return;
    }
    mValueTv.setText("onPageSeleted-Value:" + position + "--" + SystemClock.currentThreadTimeMillis());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM