2017-02-15 5 views
1

Androidでは、コンテンツ(コンテンツ)でビュー(アクティビティ/フラグメント)を更新する必要がありますか?データ/コンテンツを含むビューを更新するベストプラクティス?

TextViewはsがOnCreate()が実行されている同じスレッドからテキストを設定しないでください」、正しいが、代わりにUIスレッドに文を掲載することにより行われる(UIスレッド上で設定MessageQueue )?私のビューの設定データの

95%(TextViewsで、TabHostsCheckboxes、等...)直接OnCreate()(またはそれから呼び出される関数)とは、正常に動作しますが、私は実現で今はちょうどb/c私はそれが正しいことを意味するわけではありません(はい私は今ビットを取得しています。

ただし、UIスレッド上で実行されていることは、十分ではありません、私は予想通りRecordViewが更新されることを100%保証するためにOnResume()から投稿する必要が見つけることです。

  1. ショー以下のコードは、UpdateView()を呼び出すための2つのシナリオです。それは十分予想通りRecordViewは、人口データを表示する、またはこれを行うのより良い、より正確なおよび/または好ましい方法があることを確認するためにOnResume()UpdateView()を呼び出すことですか?

  2. はまた、_containerへの冗長_thisViewのですか?

  3. です、それはOnCreate()表示されているのと同じRecordViewと呼ばれていたさRecordViewRecordViewOnCreate()に膨らませてから返却する必要があるのはなぜですか? OnCreate()が呼び出される前に、ランタイムによって自動的に実行されるべきではありません(これはFactoryパターンなのでしょうか?)


例コード

public class RecordView : Fragment 
{ 
    private Bundle _bundle; 
    private ViewGroup _container; 
    private LayoutInflater _inflater; 

    ViewGroup _thisView; 
    TextView _tvTitle, _tvField1, _tvField2; 

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) 
    { 
     base.OnCreateView(inflater, container, bundle); 

     _inflater = inflater; 
     _container = container; 
     _bundle = bundle; 

     Render(); 

     return _thisView; 
    } 

    public override void Render() 
    { 
     _thisView = (ViewGroup) _inflater.Inflate(Resource.Layout.Record, _container, false); 

     _tvTitle = _thisView.FindViewById<TextView>(Resource.Id.tv_title);   
     _tvField1 = _thisView.FindViewById<TextView>(Resource.Id.tv_field_1); 
     _tvField2 = _thisView.FindViewById<TextView>(Resource.Id.tv_field_2); 

     // *A* SOMETIMES WORKS - Title & fields sometimes blank 
     UpdateView(); 

     // *B* SOMETIMES WORKS - Title & fields sometimes blank 
     _thisView.Post(() => { UpdateView(); }); 
    } 

    public override void OnResume() 
    {  
     base.OnResume(); 

     // *C* SOMETIMES WORKS - Title & fields sometimes blank 
     UpdateView(); 

     // *D* ALWAYS WORKS - Title & fields always display data as expected 
     _thisView.Post(() => { UpdateView(); }); 
    } 

    private void UpdateView() 
    {   
     _tvTitle.Text = "Todo";    
     _tvField1.Text = "RTFM"; 
     _tvField2.Text = "ASAP";    
    } 
} 
+0

** 'OnResume() '**からのビューの更新は確かに信頼性は向上しましたが、かなり遅くなりました(この遅さは** OnCreateView()のコンテンツ設定に干渉していた可能性があります**)ビジーなレンダリングです)。しかし、ビューの複雑さにかかわらず、** OnResume()**によって導入されたこの遅延は一貫しているように見えます(関連するビューはすべて同じViewPagerのフラグメントです**)。この遅れをよく説明します)。 – samosaris

答えて

1

あなたがバックグラウンドで初期データやOnCreateView(..)におけるいくつかのローディングアニメーション、負荷データを表示し、それが後にメインスレッド上で、実際のコンテンツを投稿する必要があります利用可能なiE:あなたがあなたのケースTextView.setText(..)には、View.set(..)のいずれかの方法を使用する場合 new Handler(Looper.GetMainLooper()).post(() => { //update views here });

また、OnCreateView(..)View'sコンテンツを設定することは、常に動作します。 これは、セッターがビューにinvalidate()を呼び出し、次にビューを再描画するためです。

TextView'sのテキストがOnCreateView(..)に設定されていることが画面上で更新されないように設計されています。

私は忘れてしまった いいえ、_thisViewは_containerと同じではありません。 _thisViewは_containerの直接の子です。

これを考慮してください: あなたのメインのlayout.xmlFrameLayoutです。 frag.xmlというレイアウトを持つFragmentを追加します(TextView)。

_containerはFrameLayoutですが、_thisViewはTextViewです。

+0

** 'Looper.GetMainLooper' **すべてのスタックトレースの最上部に表示される同じルーパースレッド**' android.os.Handler.dispatchMessage' ** <** 'android.os.Looper.loop' * * <** 'android.app.ActivityThread.main' **?明確な答えをありがとう。 – samosaris

+1

はいそうです。メインルーパはView drawing、入力処理(Touchなど)を処理します。実際、ビューの内容はメインスレッド上でのみ変更することができます。その理由はUIスレッドとも呼ばれます。したがってsetText(..)の呼び出しはメインルーパーで行わなければなりません。 – CrowsNet

+0

スレッドはメモリを共有することができます(主な利点の1つ)、他のスレッドがビューやコア設計/実装の結果を変更できないようにすることが技術的な決定だったのでしょうか。いずれにせよ、私は今、それが本当にどのように動作するかを知っています。スレッド間通信には相互排他性とそれに伴うすべての面白いオーバーヘッド(レース/ロック)が必要であるため、プログラミングを単純化することを賭けることになります。それは私が想像していた学習曲線を上回ります。 – samosaris

関連する問題