Androidプログラミング権威ガイド(第2版)学習ノート(十七)-第17章Master-Detailユーザーインタフェース

6460 ワード

この章では,2面fragmentのレイアウトをどのように書くかを紹介し,要求に合致するデバイスを適切に配置し,コールバックインタフェースの使用も紹介した.GitHubアドレス:完成17章
タブレットデバイスにとって、ユーザーインタフェースからプライマリを使用するとより良い体験が得られます.この章では、データを伝達する方法を探究します.
1.レイアウトの柔軟性を高める
2ページレイアウトを実現するには、次のタスクを実行する必要があります.
  • SingleFragmentActivityを変更し、ハードコーディングされていないインスタンス化レイアウト
  • を修正する.
  • は、2つのfragmentコンテナを含むレイアウト
  • を作成する.
  • CrimeListActivityを修正し、携帯電話機器で単面レイアウトをインスタンス化し、タブレット機器で二面レイアウトをインスタンス化する
  • を実現する.
    1.1抽象クラスSingleFragmentActivityの変更
    ここにprotectedメソッドを追加して、SingleFragmentActivityを継承するactivityに対して、必要なResIdを返すために関数を書き換えることができます.
    @LayoutRes
    protected int getLayoutResId() {
        return R.layout.activity_fragment;
    }
    

    1.2別名リソースの使用
    最小スクリーン幅600 dpのデバイスに2面インタフェースを使用させ,他のデバイスに1面インタフェースを使用させると,異なるデバイスに対して使用レイアウトが異なる.異なるデバイスに異なるレイアウトリソースを使用させるには、次の2つの方法があります.
  • res/layout/ディレクトリ内のファイルにリソース修飾子を使用させます.activity_masterdetail.xmlレイアウトファイルを使用する場合は、activity_fragment.xmlのコンテンツをres/layout/activity_masterdetail.xmlにコピーし、activity_twopane.xmlのコンテンツをres/layout-sw600dp/activity_masterdetail.xmlにコピーする必要があります.このような最も明らかな欠点は、レイアウトファイルごとにコピーされるため、データ冗長性です.
  • 別名リソースを使用します.別名リソースは、他のリソースを指す特殊なリソースです.res/values/ディレクトリに格納され、refs.xmlファイルに約束通りに定義されます.例えば、デフォルトのvaluesフォルダの下にrefs.xmlを新規作成し、コードを書き込む:
    
    
        @layout/activity_fragment
    
    
    最小幅600 dpのrefs.xml(values-sw 600 dpディレクトリの下)を新規作成し、2面のlayoutリソース:
    
    
        @layout/activity_twopane
    
    
    を書き込む.これにより、CrimeListActivityではR.layout.activity_masterdetailを参照すれば
  • になる.
    2.Activity:Fragmentの管理者
    fragmentの独立性を保証するために、管理者の仕事を理解する必要はありませんが、fragmentのライフサイクルが終了していないときにデータを渡すには、コールバックインタフェースを使用します.
    コールバックは依頼に相当し、まずfragmentがコールバックのインタフェースを自分で定義し、管理されたacitivityがこのインタフェースを実現し、fragmentは自分で定義したインタフェースを実現したオブジェクトを持って、自分がリアルタイムで呼び出すことができるようにする必要がある.
    1つのコールバックインタフェースにとってfragmentは、このインタフェースを実現するクラスが関数の中で何をしなければならないのかだけを要求しているが、実現クラスが何をするのか分からない.各実現クラスには独自の方法がある.
    2.1 CrimeListFragmentのコールバックインタフェース
    CrimeListFragmentでは、リストのいずれかをクリックすると、コールバックインタフェースの定義は次のようになります.
    public interface Callbacks {
        void onCrimeSelected(Crime crime);
    }
    

    次に、CrimeListActivity:
    //    implement      
    @Override
    public void onCrimeSelected(Crime crime) {
        //               fragment     id,
        //        activity       
        if (findViewById(R.id.detail_fragment_container) == null) {
            Intent intent = CrimePagerActivity.newIntent(this, crime.getId());
            startActivity(intent);
        } else {
        //      detail      fragment    
            Fragment newDetail = CrimeFragment.newInstance(crime.getId());
    
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.detail_fragment_container, newDetail)
                    .commit();
        }
    }
    

    CrimeListFragmentに実装インタフェースのactivityのリファレンスを保持し、メモリの回収のためにライフサイクルの最後にリファレンスを除去します.
    // CrimeListFragment
    private Callbacks mCallbacks;
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mCallbacks = (Callbacks) context;
    }
    
    //      ……
    
    @Override
    public void onDetach() {
        super.onDetach();
        mCallbacks = null;
    }
    

    最後にonClickイベントを変更し、mCallbacks.onCrimeSelected(Crime crime)を呼び出せばよい.これにより、ダブルレイアウトビューでリストのいずれかをクリックすると、詳細レイアウトに該当する情報が表示されます.
    しかし、1つの問題は、詳細ページ(CrimeFragment)で情報を変更し、リストページでは何の応答もなく、CrimeListFragmentは一時停止しないのでリフレッシュもしないので、次はCrimeFragmentでコールバックインタフェースを定義し、管理activityにCrimeListFragmentを更新させることです.
    2.2 CrimeFragmentのコールバックインタフェース
    まずコールバックインタフェースを定義します.ここで管理者にしてもらいたいのは、Crimeの詳細が更新されたときにリストを更新することです.
    // CrimeFragment
    private Callbacks mCallbacks;
    
    public interface Callbacks {
        void onCrimeUpdated(Crime crime);
    }
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mCallbacks = (Callbacks) context;
    }
    
    //      ……
    
    @Override
    public void onDetach() {
        super.onDetach();
        mCallbacks = null;
    }
    

    このインタフェースは、CrimeListActivityで実装されます.
    @Override
    public void onCrimeUpdated(Crime crime) {
        CrimeListFragment listFragment = (CrimeListFragment)
                getSupportFragmentManager()
                        .findFragmentById(R.id.fragment_container);
        listFragment.updateUI();
    }
    

    CrimeFragmentを管理するactivityはコールバックインタフェースを実装すべきであるため、CrimePagerActivityに空のインタフェース実装を提供する
    その後、データが変更されるたびにmCallbacks.onCrimeUpdated(mCrime);を呼び出せばよい.本には更新モデル層も一緒に置かれている.
    3.チャレンジの後遺症:クリムの削除
    私たちがToolBarの章で加わった挑戦を覚えていますか.Crimeを削除することです.CriminalIntentというアプリケーションでは、2面と1面の削除操作には異なる結果があるはずですが、これらの行為は本に定義されていないので、次の補充プログラムを書く方法を確立するために、自分で解決策を考えています.
  • の2面の画面の下で、左のリストから削除すべき項目を削除するにはクリックし、詳細ページもすでに存在するいずれかの詳細に変更し、実現を容易にするために、ここではすでに存在する最初の項目に変更します.最後の項目だけが削除されている場合は、右側が空白になるはずです.
  • 単面の画面の下で、削除をクリックして直接このレコードを削除し、activityを終了します.

  • ここではCrimeFragmentのCallbacksインタフェースにonCrimeDelete(Crime crime)メソッドとonCrimeAllDeleted(Crime crime)メソッドを加え、CrimeListActivityでは以下のように実現しています.
    @Override
    public void onCrimeDeleted(Crime crime) {
        //          ,       Crime   ,
        //          Crime,             Crime
        onCrimeSelected(crime);
    }
    
    @Override
    public void onCrimeAllDeleted(Crime crime) {
        //       ,      fragment   
        CrimeFragment fragment = (CrimeFragment)
                getSupportFragmentManager()
                        .findFragmentById(R.id.detail_fragment_container);
        if (fragment != null) {
            getSupportFragmentManager()
                    .beginTransaction()
                    .remove(fragment)
                    .commit();
        }
        //        
        onCrimeUpdated(crime);
    }
    

    CrimePagerActivityでもこの2つの方法を実現するが,このactivityではfinish()を行えばよい.
    「≪削除|Delete|Essbase_Studio≫」ボタンの選択したリスナーで、次の操作を行います.
    CrimeLab.get(getActivity()).deleteCrime(mCrime);
    if (CrimeLab.get(getActivity()).getCrimes().isEmpty()) {
        mCallbacks.onCrimeAllDeleted(mCrime);
    } else {
        mCrime = CrimeLab.get(getActivity()).getCrimes().get(0);
        mCallbacks.onCrimeDeleted(mCrime); //           
        updateCrime(); //                 
    }
    return true;
    

    これでプログラム全体が完成しました~
    GitHub Page: kniost.github.io :http://www.jianshu.com/u/723da691aa42