web-dev-qa-db-ja.com

フラグメント内のビューを更新する

私はこのような多くの質問を検索しましたが、どの質問にも私の答えは見つかりませんでした。

アクションバーからアクセスできる3つのタブがあるアクティビティがあります。ビュークラスを拡張して作成したカスタムビューを拡張する3つのフラグメントを追加することで、これを実現しました。

データベースが変更された瞬間に、私はinvalidate()/ postinvalidate()を呼び出してタブのビューを更新しようとしましたが、これは機能しません。同じことは、私が検討した他の多くのオプションと同じように、フラグメントのonCreateViewを呼び出す場合にも当てはまります。

しかし、別のタブに戻って戻ると、変更が加えられており、ビューが更新されています。

別のタブに変更したときに起こる同じことをどのようにシミュレートできますか?何が起こりますか。私はそれを理解するためにフラグメントのライフサイクル(onCreateView()を呼び出そうとしました)を調べようとしましたが、本来のように更新/再描画したくありません。

別のタブに切り替えるとデータが変更されるため、データは正しく読み込まれます。

不要になったコードの一部を削除しました。変更を通知するために、独自のObserverパターンの代わりにCursorloadersを実装しました。これが今の私の主な活動です。

問題は、これらのフラグメント内のビューを再描画したい場合、どうすればよいかです。 fragmentObject.getView()。invalidate()を適用しても機能しません。以前と同じ問題が発生していますが、データベースの変更を通知するオブザーバーがローダーで適切に実装されています。

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) {
}
}
19
J. Maes

フラグメント内のビューを更新する回避策を見つけました。データベースが更新されるたびに(新しいCustomView)ビューを再作成しました。その後、setContentView(CustomView view)を呼び出します。それはハックのように見えますが、それは機能し、私が試した他には何もしません。

私の問題は実際には解決されませんでしたが、アレックスロックウッドに報酬を与えました。ローダーに関する彼の助言は私のアプリケーションをより良くし、それが私が最終的に見つけた解決策を探し続けるようにさせました。

3
J. Maes
  1. onCreateView()を自分で呼び出そうとしないでください...これはライフサイクルメソッドであり、フレームワークからのみ呼び出す必要があります。

  2. Fragmentsは再利用可能なUIコンポーネントです。彼らは独自のライフサイクルを持ち、独自のビューを表示し、独自の行動を定義します。 Activityの動作は自己完結型であり、特定のFragmentから独立している必要があるため、通常、Fragmentの内部でActivityを操作する必要はありません。

    とはいえ、最善の解決策は、Fragmentsのそれぞれに_LoaderManager.LoaderCallbacks<D>_インターフェースを実装させることです。各FragmentLoaderを初期化します(つまり、SQLiteデータベースによってサポートされているCursorLoaderを使用している場合はContentProvider)。そのLoaderが(1)バックグラウンドスレッドにデータをロードし、(2)コンテンツの変更をリッスンしますデータソースに対して行われ、コンテンツが変更されるたびに新しいデータをonLoadFinished()に配信します。

    このソリューションは完全にイベント駆動型であるため、現在のソリューションよりも優れています。データがonLoadFinished()に配信されたときにのみビューを更新する必要があります(新しいタブをクリックするたびにデータソースが変更されているかどうかを手動で確認する必要はありません)。

  3. 怠惰で簡単な解決策が必要な場合は、FragmentonResume()メソッドでもビューを更新して問題を解決できる可能性があります。

21
Alex Lockwood

私は次の方法で解決できる同様の(同一ではない)問題を抱えていました:

追加したフラグメントで

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

フラグメントのビューmyViewを更新したいときに、このメソッドをアクティビティから呼び出しました。 post()を使用すると、描画の準備ができたときにのみビューが無効化されます。

4
Jörg Eisfeld

同じ問題がありました。私の解決策は、フラグメントをデタッチして再度アタッチすることでした。

        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;
2
mc.dev

私にとって最も速い解決策:

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