简体   繁体   English

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

[英]Android - Reload Fragment into a ViewPager

I'm building an App which extracts data from a SQLite local database. 我正在构建一个从SQLite本地数据库提取数据的应用程序。

I have an Activity, in which I use a ViewPager ; 我有一个Activity,在其中使用ViewPager in this ViewPager, there are 12 swipable Fragments. 在此ViewPager中,有12个可滑动片段。

I'd like to implement a " Reload " button which allows user to reload the actual Fragments, removing any changes caused by user modifications and resuming the original state of Fragment. 我想实现一个“ 重新加载 ”按钮,该按钮允许用户重新加载实际的Fragments,删除用户修改引起的任何更改并恢复Fragment的原始状态。

I tried to use notifyDataSetChanged() method on myAdapter (an extension of FragmentStatePagerAdapter ) even if it should reload the whole pager: this method works (each Fragment is reloaded), but user modifications are not removed (for example, if I get an EditText and if I replace its text, pushing "Reload" button doesn't resume its original state). 我尝试在myAdapter( FragmentStatePagerAdapter的扩展notifyDataSetChanged()上使用notifyDataSetChanged()方法,即使它应该重新加载整个寻呼机:此方法也可以工作(每个Fragment重新加载),但是不会删除用户修改(例如,如果我得到一个EditText)并且如果我替换了其文本,则按“重新加载”按钮不会恢复其原始状态)。

I also tried to replace getItemPosition() method as suggested, but it doesn't solve the problem. 我还尝试按照建议替换getItemPosition()方法,但不能解决问题。

1) Activity: 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) Adapter: 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 (1 of 12): 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();
             }
            });
        }
    }
}

EDIT #1 (about user yshahak's question) 编辑#1 (关于用户yshahak的问题)

3b) Details of method acquire(myFragmentView); 3b)详细的方法acquire(myFragmentView); from MyFragment01 , which is called to inflate elements: 来自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 class: 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);
    }
}

EDIT #2 编辑#2
When i press 'Reload' button, these methods are called from MyFragment01 (checked by some breakpoints on debug): 当我按下“重新加载”按钮时,这些方法从MyFragment01中调用(在调试时通过一些断点检查):
1. onCreateView 1. onCreateView
2. acquire(myFragmentView) 2. acquire(myFragmentView)
3. populate() 3. populate()
And if I check my EditText's text, it's correctly reloaded at the start value, so it seems that "new Fragment" is reloaded, but not attached to ViewPager element. 并且,如果我检查了EditText的文本, ViewPager正确地将其重新加载到起始值,因此似乎已重新加载了“新片段”,但未附加到ViewPager元素上。

Example: 例:
- Start value: Text -起始值: 文字
- Modified value: Text 1234 -修改值: 文字1234
- Hitting 'Reload', actual value: Text 1234 -点击“重新加载”,实际值: 文本1234
- getText().toString() from EditText: Text (expected result, not shown on actual view) -EditText中的getText()。toString(): 文本 (预期结果,未在实际视图中显示)

Lets try to look it slowly: 让我们尝试慢慢看一下:

When you hit the "test" Button, what happens is the adpater bring all it Fragments and ask itself what to do with them. 当您按下“测试”按钮时,发生的事情是adpater将所有片段都带进去,并问自己如何处理它们。 If you had use FragmentPageAdapter then because you define that it will throw them (with the "POSITION_NONE") it would had reload all Fragments by calling it getItem(); 如果使用FragmentPageAdapter,则因为定义了它将抛出它们(带有“ POSITION_NONE”),所以它将通过调用getItem()来重新加载所有Fragment。

But because you use FragmentStatePagerAdapter extension it try to use it old Fragments so the old modification remain. 但是由于使用FragmentStatePagerAdapter扩展,因此尝试使用旧的Fragments,因此保留了旧的修改。

So basically I think that id you replace to FragmentPageAdapter it should work. 所以基本上我认为您替换为FragmentPageAdapter的id应该可以使用。

Keep in mind that this approach not really efficient to reload all Fragments just because you want to update one of them. 请记住,仅因为您要更新其中一个片段,这种方法才能真正有效地重新加载所有片段。

I found a solution for my problem. 我找到了解决问题的方法。 Inside Adapter , I added FragmentManager fm as variable in constructor: Adapter内部,我将FragmentManager fm添加为构造函数中的变量:

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

Inside MyActivity , I've just edited reloadFragment() method in this way, now that FragmentManager is available: 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
    }
 }

Calling my populate() custom method on each Fragment, every EditText (and general elements) is correctly restored to its original value. 在每个Fragment上调用我的populate()自定义方法,每个EditText(和常规元素)都将正确恢复到其原始值。

The argument position of reloadFragment(int position) is provided when I click on Reload button. 当我单击“重新加载”按钮时,将提供reloadFragment(int position)的参数position reloadFragment(int position) I moved the method on a general class in order to call it from each fragment I want. 我在通用类上移动了该方法,以便从我想要的每个片段中调用它。 Because of this, I needed to add view and activity in arguments: 因此,我需要在参数中添加视图和活动:

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);
        }
    });
}

Maybe it's not the most efficient solution ever, if I'll find a better general solution, I'll publish it here 也许这不是有史以来最有效的解决方案,如果我能找到更好的一般解决方案,我会在这里发布

EDIT #1 : I have to modify the way to implement the control, As yshahak told me, List is not a good way to solve my problems. 编辑#1 :我必须修改实现控件的方式,正如yshahak告诉我的那样,List并不是解决我的问题的好方法。 That's why, when I open my activity, Fragment are not attached in order (from 0 to 11), but "on demand". 这就是为什么当我打开活动时,片段未按顺序(从0到11)附加,而是“按需”附加的原因。 So if I open my activity and if I swipe directly to 11th Fragment, that will be element number 3 instead of 11 (because my Activity cache only first 2 Fragment onCreate). 因此,如果我打开活动并直接滑动到第11个片段,则它将是元素编号3而不是11(因为我的活动仅缓存前两个2个片段onCreate)。 I will search for another solution and I'll update here 我将寻找另一个解决方案,我将在这里更新

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

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