刷新片段内的视图

Posted

技术标签:

【中文标题】刷新片段内的视图【英文标题】:Refreshing a view inside a fragment 【发布时间】:2012-09-24 04:40:52 【问题描述】:

我已经搜索了许多看起来像这个问题的问题,但都没有找到我的答案。

我的活动有 3 个可通过操作栏访问的选项卡。我通过添加 3 个片段来扩展我扩展视图类的自定义视图来实现这一点。

在数据库更改的那一刻,我尝试通过调用 invalidate()/postinvalidate() 来刷新选项卡中的视图,但这不起作用。就像我考虑的许多其他选项一样,调用片段的 onCreateView 也是如此。

但是,当我转到另一个选项卡并返回时,已进行更改,并且我的视图已按应有的方式更新。

如何模拟切换到另一个选项卡时发生的相同情况?会发生什么。我试图查看 Fragment 生命周期(试图调用 onCreateView())来弄清楚,但它只是不想按应有的方式刷新/重绘。

数据已正确加载,因为当我切换到另一个选项卡时数据已更改。

我删除了一些代码,因为它不再相关。我实现了 Cursorloaders 而不是我自己的观察者模式来通知更改。这是我现在的主要活动。

问题是,如果我想重绘这些片段中的视图,我现在应该怎么做。如果我应用 fragmentObject.getView().invalidate() 它不起作用。我遇到了和以前一样的问题,但是现在我的 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) 


【问题讨论】:

也许你可以用 savedInstanceState 做点什么?如果您阅读了随 android API 提供的数据库教程,您将看到一个部分,如果 savedInstanceState 更改或未更改,则该部分会阻止执行操作。我记不清了。也许您可能会导致 savedInstanceState 被重置,这会导致数据库更新提示视图刷新?只是一个想法。 我注意到您没有对Fragment#getView() 进行任何调用... 由getView() 返回的视图不是您要操纵的视图吗?也许视图没有被重新绘制的原因是因为您没有更新正确的视图? 在目前的情况下我不叫这个。我尝试调用 editFragment.getView().invalidate();在观察者中,它被调用但它不起作用。我以其他方式调用了正确的视图,方法是将其作为参数传递给也调用上述 ArchitectureData 类中的 addNode() 方法的方法 【参考方案1】:

    不要尝试自己调用onCreateView()...这是一个生命周期方法,只能由框架调用。

    Fragments 是可重用的 UI 组件。他们有自己的生命周期,展示自己的观点,定义自己的行为。你通常不需要让你的Activity 搞乱Fragment 的内部工作,因为Fragment 的行为应该是独立的,并且独立于任何特定的Activity

    也就是说,我认为最好的解决方案是让您的每个Fragments 实现LoaderManager.LoaderCallbacks&lt;D&gt; 接口。每个Fragment 将初始化一个Loader(即,如果您使用由SQLite 数据库支持的ContentProvider,则为CursorLoader),并且Loader 将负责(1)在后台加载数据线程,以及 (2) 侦听对数据源所做的内容更改,并在内容更改发生时将新数据传递给onLoadFinished()

    此解决方案比您当前的解决方案更好,因为它完全是事件驱动的。您只需在数据传送到onLoadFinished() 时刷新视图(而不必在每次单击新选项卡时手动检查数据源是否已更改)。

    如果你很懒,只想快速解决问题,你也可以在 FragmentonResume() 方法中刷新视图。

【讨论】:

感谢您的回答和见解 :)。目前优先级很快,所以我首先尝试了您的第三个解决方案,但没有奏效。此时,与我的 Contentprovider 通信的类实现了 Observable,我的片段内的视图(或者当我尝试 onCreateView 事物时我的片段)实现了 Observer。这样,更新我的数据库时调用了 update 方法,我尝试调用 invalidate/onCreateView/onResume/... 。我认为这也是事件驱动的。明天我会仔细看看你的第二个解决方案,因为我不熟悉装载机。 @J.Maes 我已经写了很多关于Loaders 的文章,以this blog post 开头...也许会有所帮助。 CursorLoader 会自动在其Cursor 上注册一个ContentObserver,因此只要您的ContentProvider 在对数据库进行更改时在query()ContentResolver#notifyChange(...) 中调用Cursor#setNotificationUri(...)CursorLoader 就会加载新数据并将其交付给onLoadFinished()。实现自己的ContentObserver 可能会使事情复杂化... 我知道这个实现会更好,但你能说一下与当前情况相比,更新和不更新之间的区别吗?我目前与我自己的观察者的解决方案并不是真正的解决方案,因为我的新数据没有显示(实际绘制)。我快速浏览了您的博文,据我所知,当数据发生变化时,我将不得不在 onLoadFinished()/另一种方法中做一些事情,但是我必须放在那里以确保我的数据被绘制.编辑/你的教程的结构是我见过的最好的 g+1 之一 @J.Maes 感谢您的 +1。 :) 嗯...好吧,我建议的所有Loader 内容都是在您的View 正确实施的假设下制作的。看起来情况就是这样,当您在选项卡之间切换时更改会更新(我认为这是因为Fragments 在片段关闭/打开屏幕时完全被破坏/重新创建)。因此,鉴于所有这些,我敢打赌,问题在于您当前在 Fragment 中更新视图的方式不正确。这可能是FragmentView 的问题... @J.Maes 您能否发布一些您目前拥有的代码来说明您如何通知/设置视图的新数据?【参考方案2】:

我有一个类似(虽然不相同)的问题,我可以通过以下方式解决:

在我添加的片段中

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

当我想刷新片段的视图 myView 时,我从活动中调用了此方法。 post() 的使用确保了视图只有在准备好被绘制时才会失效。

【讨论】:

你如何从活动中调用这个方法?我们错过了您回答中的重要部分。【参考方案3】:

我找到了一种解决方法来刷新我的片段中的视图。每次更新数据库时,我都会重新创建(新的 CustomView)视图。之后我调用 setContentView(CustomView view)。它看起来更像是一种 hack,但它确实有效,而我尝试过的其他方法都没有。

虽然我的问题并没有真正解决,但我还是把奖励给了 Alex Lockwood。他对 Loaders 的建议使我的应用程序变得更好,并促使我继续寻找最终找到的解决方案。

【讨论】:

对不起,我不能提供太多建议...我以前从未真正实现过我自己的自定义视图,所以我没有什么可以放弃的。我很高兴您找到了解决方法,并且我帮助您改进了您的应用程序。 :) @J.Maes 我也有同样的要求,能否告诉你你创建了一个 CustomView 并用它来设置内容视图。【参考方案4】:

我有同样的问题。 我的解决方案是分离片段并重新附加它。

        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;

【讨论】:

Mik 的“修复”也对我有用....有谁知道更优雅的解决方案或可以解释为什么会这样? 这会进入 Activity 内部吗? 基本上是的。 getSupportFragmentManager() 是 FragmentActivity 的一个方法。但是,只要您有 FragmentManager 实例,您就可以放在任何地方。【参考方案5】:

最适合我的解决方案:

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

【讨论】:

以上是关于刷新片段内的视图的主要内容,如果未能解决你的问题,请参考以下文章

从列表视图中删除一行后刷新片段

是否可以刷新片段的视图

如何刷新片段上的列表视图

片段中的 notifyDataSetChanged() 不刷新列表视图

无法从 ViewPager 中的另一个片段刷新/更新片段中的列表视图

在 ViewPager 中刷新 Fragment 视图