Android - 将片段重新加载到ViewPager中

时间:2015-07-01 08:48:10

标签: java android android-viewpager fragmentstatepageradapter

我正在构建一个从SQLite本地数据库中提取数据的应用程序。

我有一个Activity,其中我使用 ViewPager ;在这个ViewPager中,有12个可转换的碎片。

我想实现一个“ Reload ”按钮,允许用户重新加载实际的片段,删除用户修改引起的任何更改并恢复片段的原始状态。

我尝试在myAdapter上使用 notifyDataSetChanged() 方法( FragmentStatePagerAdapter 的扩展名),即使它应该重新加载整个寻呼机:此方法工作(重新加载每个片段),但不删除用户修改(例如,如果我得到一个EditText,如果我替换它的文本,按“重新加载”按钮不会恢复其原始状态)。

我还尝试按建议替换 getItemPosition() 方法,但它无法解决问题。

1)活动:

public class MyActivity extends AppCompatActivity {
//code
    ViewPager pager;
    MyAdapter adapter;
    TabLayout tabLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //...
        //Pager settings
        adapter = new Adapter(getSupportFragmentManager(),this);
        pager = (ViewPager) findViewById(R.id.pager);
        pager.setAdapter(adapter);
        //TabLayout settings
        tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
        tabLayout.setupWithViewPager(pager);
        //...
    }
    //...
    //Method called after clicking on 'Reload' button
    public void reloadFragment() {
        adapter.notifyDataSetChanged();
    }
}

2)适配器:

public class Adapter extends FragmentStatePagerAdapter {
    //...
    public Fragment getItem(int position) {
        Fragment f = null;
        switch (position) {
            case 0:
                f = new MyFragment01();
                break;
            //case from 0 to 11
        }
        return f;
    }
    //...
    @Override
    public int getItemPosition( Object object ) {
        return POSITION_NONE;
    }

3)MyFragment01(12个中的1个):

import android.support.v4.app.Fragment;
//...
public class MyFragment01 extends Fragment {
    PopulateEditText editText01;
    public MyFragment01() {
        //Empty constructor used to load from MyActivity
    }
    @Override
    public void onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //...
        View myFragmentView = inflater.inflate(R.layout.layout_fragment_01, container, false);
        //...
        acquire(myFragmentView); //Acquire layout elements (EditTexts, Spinners, other)
        populate(); //Insert text on previous layout elements, based on SQLite data
        //...
        //'Reload' button
        ImageButton test = (ImageButton) myFragmentView.findViewById(R.id.testBtn);
        test.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ((MyActivity)getActivity()).reloadFragment();
             }
            });
        }
    }
}

编辑#1 (关于用户yshahak的问题)

3b)来自acquire(myFragmentView);的方法 MyFragment01 的详细信息,该方法被调用以夸大元素:

public void acquire(View myFragmentView) {
    editText01 = new PopulateEditText(R.id.editText01,myFragmentView);
    //...
}
public void populate() {
    //cursor is a cursor which extracts a record from SQLite Database
    //column is an attribute of this record
    editText01.initializeEditText(cursor,"column",true);
    //...
}

4)PopulateEditText类:

public class PopulateEditText {
    EditText editText;
    Activity activity;
    //Constructor
    public PopulateEditText(int elementFromLayout, View myFragmentView) {
        this.editText=(EditText) myFragmentView.findViewById(elementFromLayout);
        reset();
    }
    public void reset() {
        if(editText!=null)
            editText.setText("");
    }

    public void initializeEditText(Cursor c, String column, boolean enableEditText) {
        this.column=column;
        String s = c.getString(c.getColumnIndex(column));
        editText.setText(s);
        editText.setSelection(editText.getText().length());
        editText.setEnabled(enableEditText);
    }
}

编辑#2
当我按下“重新加载”按钮时,这些方法从MyFragment01调用(在调试时通过某些断点检查):
1. onCreateView
2. acquire(myFragmentView)
3. populate()
如果我检查我的EditText文本,它会在起始值处正确重新加载,所以似乎重新加载了“new Fragment”,但没有附加到ViewPager元素。

例:
- 起始值:文字
- 修改后的值:文本1234
- 点击'重新加载',实际值:文本1234
- 来自EditText的getText()。toString(): Text (预期结果,未在实际视图中显示)

2 个答案:

答案 0 :(得分:0)

让我们慢慢看一下:

当你点击“测试”按钮时,会发生什么是adpater带来所有碎片并问自己如何处理它们。如果您已经使用了FragmentPageAdapter,那么因为您定义了它将抛出它们(使用“POSITION_NONE”),它将通过调用它来重新加载所有片段getItem();

但是因为你使用了FragmentStatePagerAdapter扩展,所以尝试使用旧的Fragments来保留旧的修改。

所以基本上我认为你替换为FragmentPageAdapter的id应该可以工作。

请记住,这种方法并不是真正有效地重新加载所有片段只是因为你想更新其中一个片段。

答案 1 :(得分:0)

我找到了解决问题的方法。 在Adapter内,我在构造函数中添加了FragmentManager fm作为变量:

FragmentManager fm;
public Adapter(FragmentManager fm, Activity activity) {
    super(fm);
    this.fm=fm;
    this.context=activity.getApplicationContext();
    this.activity=activity;
}

MyActivity内,我刚刚以这种方式编辑了reloadFragment()方法,现在FragmentManager可用了:

public void reloadFragment(int position) {
    Adapter adapter = (Adapter)pager.getAdapter();
    //This list contains a 'list' of Fragments available on ViewPager adapter. 
    List<Fragment> list = adapter.fm.getFragments();
    switch(position) {
        case 0:
            ((MyFragment01)list.get(position)).populate();
            break;
        //iterate for case from 0 to 11
    }
 }

在每个片段上调用populate()自定义方法,每个EditText(和常规元素)都会正确恢复为原始值。

单击“重新加载”按钮时,会提供position的参数reloadFragment(int position)。我将方法移动到一般类上,以便从我想要的每个片段中调用它。 因此,我需要在参数中添加视图和活动:

public static void reloadButton(View myFragmentView, final Activity activity, final int position) {
    ImageButton test = (ImageButton) myFragmentView.findViewById(R.id.reloadBtn);
    test.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ((MyActivity)activity).reloadFragment(position);
        }
    });
}

也许这不是最有效的解决方案,如果我能找到更好的通用解决方案,我会在这里发布

编辑#1 :我必须修改实现控件的方式,正如yshahak告诉我的,List不是解决问题的好方法。 这就是为什么,当我打开我的活动时,Fragment没有依次附加(从0到11),而是“按需”。因此,如果我打开我的活动,如果我直接滑动到第11个片段,那将是元素3而不是11(因为我的活动缓存只有前2片段onCreate)。 我将搜索另一个解决方案,我会在这里更新