简体   繁体   English

刷新片段内的视图

[英]Refreshing a view inside a fragment

I have searched the numerous questions that look like this one, but haven't found my answer in any of them. 我搜索了很多看起来像这个问题的问题,但是没有找到我的答案。

I have an activity that has 3 tabs accessible through the action bar. 我有一个活动,通过操作栏可以访问3个选项卡。 I achieved this by adding 3 fragments that inflate a custom view I made extending the view class. 我通过添加3个片段来实现这一点,这些片段扩展了我扩展视图类的自定义视图。

At the moment the database changes, I try to refresh the view in my tab by calling invalidate()/postinvalidate(), but this does not work. 在数据库更改的那一刻,我尝试通过调用invalidate()/ postinvalidate()刷新我的选项卡中的视图,但这不起作用。 The same is true for calling onCreateView of the fragment just as many other options I considered. 调用片段的onCreateView就像我考虑的其他选项一样。

When I go to another tab and go back, however, the change has been made and my view is updated as it should be. 然而,当我转到另一个选项卡然后返回时,已经进行了更改,并且我的视图会按原样更新。

How can I simulate the same thing that happens when changing to another tab? 如何模拟更改为另一个选项卡时发生的相同事情? What does happen. 会发生什么 I tried to look at the Fragment lifecycle (tried to call onCreateView()) to figure it out but it just doesn't want to refresh/redraw as it should. 我试图查看Fragment生命周期(试图调用onCreateView())来解决它,但它只是不想刷新/重绘它应该。

The data is loaded properly, as the data is changed when I change to another tab. 正确加载数据,因为当我更改为另一个选项卡时数据会更改。

I deleted some of the code as it is no longer relevant. 我删除了一些代码,因为它不再相关。 I implemented Cursorloaders instead of my own Observer pattern to notify a change. 我实现了Cursorloaders而不是我自己的Observer模式来通知更改。 This is my main activity right now. 这是我现在的主要活动。

The question is what should I do now if I want to redraw the view inside these fragments. 问题是,如果我想重绘这些片段中的视图,我现在应该怎么做。 If I apply fragmentObject.getView().invalidate() it does not work. 如果我应用fragmentObject.getView()。invalidate()它不起作用。 I'm having the same problem as before, but now my Observer to notify a change in the database is properly implemented with loaders. 我遇到了和以前一样的问题,但现在我的Observer通知加载器正确实现了数据库中的更改。

public class ArchitectureActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);     
    setContentView(R.layout.main);

    ActionBar actionbar = getActionBar();
    actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    ActionBar.Tab EditTab = actionbar.newTab().setText("Edit");
    ActionBar.Tab VisualizeTab = actionbar.newTab().setText("Visualize");
    ActionBar.Tab AnalyseTab = actionbar.newTab().setText("Analyse");

    Fragment editFragment = new EditFragment();
    Fragment visualizeFragment = new VisualizeFragment();
    Fragment analyseFragment = new AnalyseFragment();

    EditTab.setTabListener(new MyTabsListener(editFragment));
    VisualizeTab.setTabListener(new MyTabsListener(visualizeFragment));
    AnalyseTab.setTabListener(new MyTabsListener(analyseFragment));

    actionbar.addTab(EditTab);
    actionbar.addTab(VisualizeTab);
    actionbar.addTab(AnalyseTab);

    ArchitectureApplication architectureApplication = (ArchitectureApplication)getApplicationContext();
    architectureApplication.initialize();

    getLoaderManager().initLoader(0, null, this);
    getLoaderManager().initLoader(1, null, this);
}

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    if (id == 0){
        return new CursorLoader(this, GraphProvider.NODE_URI , null, null, null, null);
    } else if (id == 1){
        return new CursorLoader(this, GraphProvider.ARC_URI , null, null, null, null);
    }
    return null;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    // Reloading of data, actually happens because when switching to another tab the new data shows up fine
    Log.e("Data", "loaded");
}

public void onLoaderReset(Loader<Cursor> loader) {
}
}
  1. Don't try to call onCreateView() yourself... it's a lifecycle method and should be called only by the framework. 不要试图自己调用onCreateView() ......这是一个生命周期方法,只能由框架调用。

  2. Fragment s are re-usable UI components. Fragment是可重用的UI组件。 They have their own lifecycle, display their own view, and define their own behavior. 他们有自己的生命周期,显示自己的视图,并定义自己的行为。 You usually don't need to have your Activity mess around with the internal workings of a Fragment , as the Fragment 's behavior should be self-contained and independent of any particular Activity . 你通常不需要让你的Activity乱用Fragment的内部工作,因为Fragment的行为应该是自包含的并且独立于任何特定的Activity

    That said, I think the best solution is to have each of your Fragment s implement the LoaderManager.LoaderCallbacks<D> interface. 也就是说,我认为最好的解决方案是让每个Fragment实现LoaderManager.LoaderCallbacks<D>接口。 Each Fragment will initialize a Loader (ie a CursorLoader if you are using a ContentProvider backed by an SQLite database), and that Loader will be in charge of (1) loading the data on a background thread, and (2) listening for content changes that are made to the data source, and delivering new data to onLoadFinished() whenever a content change occurs. 每个Fragment将初始化一个Loader (即如果你使用的是由SQLite数据库支持的ContentProvider则为CursorLoader ),并且Loader将负责(1)在后台线程上加载数据,以及(2)监听内容更改对数据源进行的操作,并在发生内容更改时将新数据传递给onLoadFinished()

    This solution is better than your current solution because it is entirely event-driven. 此解决方案优于您当前的解决方案,因为它完全由事件驱动。 You only need to refresh the view when data is delivered to onLoadFinished() (as opposed to having to manually check to see if the data source has been changed each time you click on a new tab). 您只需要在将数据传递到onLoadFinished()时刷新视图(而不是每次单击新选项卡时都必须手动检查数据源是否已更改)。

  3. If you are lazy and just want a quick solution, you might be able to get away with refreshing the view in your Fragment 's onResume() method too. 如果你很懒,只想要快速解决方案,你也可以在FragmentonResume()方法中刷新视图。

I had a similar (although not identical) problem that I could solve in the following way: 我有一个类似的(虽然不完全相同)问题,我可以通过以下方式解决:

In the fragment I added 在我添加的片段中

public void invalidate() {
    myView.post(new Runnable() {
        @Override
        public void run() {
            myView.invalidate();
        }
    });
}

and I called this method from the activity when I wanted to refresh the view myView of the fragment. 当我想要刷新片段的myView时,我从活动中调用了这个方法。 The use of post() ensures that the view is only invalidated when it is ready to be drawn. 使用post()可确保视图仅在准备好绘制时失效。

I've found a workaround to refresh the view inside my fragment. 我找到了一个解决方法来刷新片段中的视图。 I recreated (new CustomView) the view every time the database has been updated. 每次更新数据库时,我都会重新创建(新的CustomView)视图。 After that I call setContentView(CustomView view). 之后我调用setContentView(CustomView视图)。 It looks more like a hack, but it works and nothing else that I tried does. 它看起来更像是一个黑客,但它有效,没有其他我尝试过的。

Although my problem was not actually solved, I gave the reward to Alex Lockwood. 虽然我的问题实际上没有解决,但我还是给Alex Lockwood奖励了。 His advice on Loaders made my application better and it caused me to keep looking for a solution that I eventually found. 他对装载机的建议使我的应用程序更好,这让我一直在寻找我最终找到的解决方案。

I had the same issue. 我遇到过同样的问题。 My solution was detach fragment and attach it again. 我的解决方案是分离片段并再次附加它。

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        Fragment f = getFragment(action);
        if(forceUpdate)
        {
            fragmentTransaction.detach(f);
            fragmentTransaction.attach(f);
        }
        fragmentTransaction.replace(R.id.mainFragment, f);
        fragmentTransaction.commit();
        currentAction = action;

The fastest solution working for me: 最快的解决方案适合我:

 @Override
    public void onPause() {
        super.onPause();
        if (isRemoving() && fragmentView != null) {
            ((ViewGroup) fragmentView).removeAllViews();
        }
    }

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

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