操作栏选项卡切换上的PullToRefreshAttacher NullPointerException

时间:2014-06-10 15:53:20

标签: android android-fragments tabs

我有一个使用ActionBar.Tab的应用程序,并实现了Chris Banes的pulltorefresh库。 在一个标签中,我有多个片段(如导航)。

如果在选项卡中我在父片段中,我可以切换选项卡而不会出现问题。 但是,如果在选项卡中我在子片段中,则在更改选项卡时会出现NullPointerException。

例外是(编辑为包含完整例外)

06-13 12:38:02.291: D/AndroidRuntime(22892): Shutting down VM
06-13 12:38:02.291: W/dalvikvm(22892): threadid=1: thread exiting with uncaught exception (group=0x4165fd40)
06-13 12:38:02.296: E/AndroidRuntime(22892): FATAL EXCEPTION: main
06-13 12:38:02.296: E/AndroidRuntime(22892): Process: com.example.myapp, PID: 22892
06-13 12:38:02.296: E/AndroidRuntime(22892): java.lang.NullPointerException
06-13 12:38:02.296: E/AndroidRuntime(22892):    at uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher.addHeaderViewToActivity(PullToRefreshAttacher.java:594)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher$2.run(PullToRefreshAttacher.java:128)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at android.os.Handler.handleCallback(Handler.java:733)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at android.os.Handler.dispatchMessage(Handler.java:95)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at android.os.Looper.loop(Looper.java:136)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at android.app.ActivityThread.main(ActivityThread.java:5102)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at java.lang.reflect.Method.invokeNative(Native Method)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at java.lang.reflect.Method.invoke(Method.java:515)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
06-13 12:38:02.296: E/AndroidRuntime(22892):    at dalvik.system.NativeStart.main(Native Method)

我在我的项目中使用Chris'代码作为库。 另外,这是我在“MainFragment”(它包含ActionBar.Tab和所有片段)中处理标签切换的方式 在星期一更新后增加

更新 在调用异常之前调用的最后一行代码:             。mActivity.getWindow()getDecorView()getWindowVisibleDisplayFrame(mRect)。 该行来自pulltorefresh.jar库中的“PullToRefreshAttacher.class”类。 这是这个类的整个方法:

protected void addHeaderViewToActivity(View headerView) {
    // Get the Display Rect of the Decor View
    mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(mRect);

    // Honour the requested layout params
    int width = WindowManager.LayoutParams.MATCH_PARENT;
    int height = WindowManager.LayoutParams.WRAP_CONTENT;
    ViewGroup.LayoutParams requestedLp = headerView.getLayoutParams();
    if (requestedLp != null) {
        width = requestedLp.width;
        height = requestedLp.height;
    }

    // Create LayoutParams for adding the View as a panel
    WindowManager.LayoutParams wlp = new WindowManager.LayoutParams(width, height,
            WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
            PixelFormat.TRANSLUCENT);
    wlp.x = 0;
    wlp.y = mRect.top;
    wlp.gravity = Gravity.TOP;

    // Workaround for Issue #182
    headerView.setTag(wlp);
    mActivity.getWindowManager().addView(headerView, wlp);
}

更新: 根据Ultimo_m的要求,这是我的课程:

类“MainFragmentActivity”包含所有片段

public class MainFragmentActivity extends FragmentActivity
{
private final String TAG_FRAGMENT_LIST = “list";

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

    ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    actionBar.setTitle(getApplicationContext().getApplicationInfo().labelRes);  

    ActionBar.Tab tab_list = actionBar.newTab().setText(“List”);
    tab_jobList.setIcon(R.drawable.text_list_white);

    Fragment fragmentList = new ListLV();

    tab_list.setTabListener(new MyTabsListener(fragmentList, TAG_FRAGMENT_LIST));

    actionBar.addTab(tab_jobList);
}

@Override
public void onBackPressed() 
{
    FragmentManager fm = getFragmentManager();
    Log.d("length out", "" + fm.getBackStackEntryCount());

    if (fm.getBackStackEntryCount() > 2) 
    {
        //do nothing since i'm on other fragments
    } 
    else 
    {
        // im are in my activity two or one so pop the fragment
        fm.popBackStack();
    }
}

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

class MyTabsListener implements ActionBar.TabListener
{
    private Fragment fragment;
    private String mTag;

    public MyTabsListener(Fragment fragment, String tag)
    {
        this.fragment = fragment;
        mTag = tag;
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) 
    {
        FragmentManager fm = getFragmentManager();
        fm.popBackStack();

        ft.replace(R.id.fragment_container, fragment);
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) 
    {
        // TODO Auto-generated method stub  
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) 
    {
        // TODO Auto-generated method stub  
    }
}   
}//end class MainFragmentActivity

Class ListLV是MainFragmentActivity类中的“父类”

public class ListLV extends ListFragment implements ResultsListener
{
Context context;
ArrayList<Job> arrayOfJobs;
DatabaseHandler db;
private PullToRefreshLayout pullToRefreshLayout;
SharedPreferences preferences;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
{
    context = inflater.getContext();
    db = new DatabaseHandler(context);
    arrayOfJobs = db.getAllJobs();

    getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    preferences = context.getSharedPreferences("com.example.myapp”, 0);

    MyListAdapter adapter = new MyListAdapter(context, arrayOfJobs);
    setListAdapter(adapter);

    return super.onCreateView(inflater, container, savedInstanceState); 
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) 
{
    super.onViewCreated(view, savedInstanceState);          

    // This is the View which is created by ListFragment
    ViewGroup viewGroup = (ViewGroup) view;

    // We need to create a PullToRefreshLayout manually
    pullToRefreshLayout = new PullToRefreshLayout(viewGroup.getContext());

    // We can now setup the PullToRefreshLayout
    ActionBarPullToRefresh.from(getActivity())
    .insertLayoutInto(viewGroup) // We need to insert the PullToRefreshLayout into the Fragment's ViewGroup
    .theseChildrenArePullable(getListView(), getListView().getEmptyView())// We need to mark the ListView and it's Empty View as pullable This is because they are not direct children of the
    // ViewGroup
    .options(Options.create()
            .refreshingText("Downloading...")
            .pullText("Pull to refresh!")
            .releaseText("Release!")
            .titleTextColor(android.R.color.black)
            .progressBarColor(android.R.color.holo_green_dark)
            .headerBackgroundColor(android.R.color.holo_green_light)
            .progressBarStyle(Options.PROGRESS_BAR_STYLE_INSIDE)
            .build())
    .listener(new OnRefreshListener() { // We can now complete the setup as desired
        @Override
        public void onRefreshStarted(View view) 
        {
            System.out.println("onRefreshStarted");
            // Get data again
        }
    })
    .setup(pullToRefreshLayout);

}


@Override
public void onListItemClick(ListView l, View v, int position, long id) 
{
    super.onListItemClick(l, v, position, id);

    // Create new fragment and transaction
    Fragment newFragment = new ListDetails();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();

    // pass data between fragments
    Job job = arrayOfJobs.get(position);
    Bundle bundle = new Bundle();
    bundle.putSerializable("job", job);
    newFragment.setArguments(bundle);

    // Replace whatever is in the fragment_container view with this fragment,
    // and add the transaction to the back stack
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);

    // Commit the transaction
    transaction.commit();
}

@Override
public void onResultsSucceeded(String result) 
{       
    arrayOfJobs.clear();
    arrayOfJobs = db.getAllJobs();

    JobListAdapter adapter = new JobListAdapter(context, arrayOfJobs);
    setListAdapter(adapter);

    Toast.makeText(context, db.getNumberOfJobs() + " jobs in SQLite", Toast.LENGTH_SHORT).show();

    pullToRefreshLayout.setRefreshComplete();
}
}//end class ListLV

Class ListDetails是ListLV类中的“child”

public class ListDetails extends Fragment
{
Job job;
Context context;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState)
{

    View view = inflater.inflate(R.layout.details, container, false);
    Bundle arguments = getArguments();
    job = (Job) arguments.getSerializable("job");
    context = inflater.getContext();

    getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);


    // setting values on widgets

    return view;

}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isVisibleToUser) {
        Activity a = getActivity();
        if(a != null) a.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }
}
}

有关如何解决此问题的任何想法? 非常感谢你。

1 个答案:

答案 0 :(得分:0)

如果你没有做任何特别的事情,你为什么要使用自定义标签监听器(MyTabsListener)? 你的主要fragmentActivity可以实现Actionbar.Tablistener。

一个例子:

public class MainActivity extends FragmentActivity implements ActionBar.TabListener {


    AppSectionsPagerAdapter mAppSectionsPagerAdapter;
    ViewPager mViewPager;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);



        // Create the adapter that will return a fragment for each of the three primary sections
        // of the app.
        mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager());

        final ActionBar actionBar = getSupportActionBar();


        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Set up the ViewPager, attaching the adapter and setting up a listener for when the
        // user swipes between sections.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mAppSectionsPagerAdapter);
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                // When swiping between different app sections, select the corresponding tab.
                // We can also use ActionBar.Tab#select() to do this if we have a reference to the
                // Tab.
                actionBar.setSelectedNavigationItem(position);
            }
        });

            // For each of the sections in the app, add a tab to the action bar.
            for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) {
                /* Create a tab with text corresponding to the page title defined by the adapter.
                 Also specify this Activity object, which implements the TabListener interface, as the
                 listener for when this tab is selected.*/
                int tabIcon = 0;
                switch (i) {
                case 0:
                    tabIcon = R.drawable.ic_tab_1;
                    break;
                case 1:
                    tabIcon = R.drawable.ic_tab_2;
                    break;
                case 2:
                    tabIcon = R.drawable.ic_tab_3;
                    break;
                case 3:
                    tabIcon = R.drawable.ic_tab_4;
                    break;

                default:
                    break;
                }
                actionBar.addTab(
                        actionBar.newTab()
                                .setIcon(tabIcon)
                                .setTabListener(this));
            }
        }
      }
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        // When the given tab is selected, switch to the corresponding page in the ViewPager.
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }



    public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {

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

        @Override
        public Fragment getItem(int i) {
            switch (i) {
                case 0:
                    return new ListLV();
                case 1:

                    return new Fragment_2();

                case 3:

                    return new Fragment_3();

                default:

                    return new Fragment_4();
            }
        }

        @Override
        public int getCount() {
            return 4;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            String tabText = "";
            switch (position) {
            case 0:
                tabText = "Tab 1";
                break;
            case 1:
                tabText = "Tab 2";
                break;
            case 2:
                tabText = "Tab 3";
                break;
            case 3:
                tabText = "Tab 4";
                break;
            default:
                break;
            }
            return tabText;
        }
    }

    }