星期四, 11月 10, 2011

Fragment (八)

Android應用程式學習筆記

Communicating with the Activity

雖然fragment可以做為物件獨立於activity,也可以使用在多個activities,預設的fragment實體是直接與activity綁定。

特別是,fragment透過getActivity()方法可以存取Activity並輕鬆地執行工作比如取得activity布局的view。


View listView = getActivity().findViewById(R.id.list);

同樣地,你的activity也可以呼叫fragment中的方法,透過findFragmentById()方法或是findFragmentByTag()方法。


ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);


Creating event callbacks to the Activity

在一些情況中,你需要一個fragment與activity分享一個事件,在fragment定義一個回呼的介面並要求寄主activity執行是一個分享事件的好方法。當activity從界面接收到回呼,介面就會將資訊分享給在布局中的其他需要的fragment。

舉例,如果新聞應用程式有兩個fragment在activity中-一個顯示文章列表(Fragment A)-其他顯示文章內容(Fragment B),當一個列表選項被選到時,Fragment A必須告訴activity以便activity可以呼叫Fragment B去顯示文章內容,在此例中,OnArticleSelectedListener介面被宣告在Fragment A中。


public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

然後fragment的寄主activity執行OnArticleSelectedListener介面並複寫OnArticleSelected()方法,去通知Fragment B來自Fragment A的事件,為了確認寄主activity實現此介面,fragment A的onAttach()回呼方法將實體化OnArticleSelectedListener的Activity傳入onAttach()方法。


public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
    ...
}

如果activity沒有執行介面,fragment就會丟出ClassCastException例外,如果成功,mListener持有activity對OnArticleSelectedListener實現的引用,所以Fragment A可以通過呼叫由OnArticleSelectedListener介面定義的方法與Activity分享事件。例如,如果fragment A繼承ListFragment,每次用戶點擊列表項目,系統呼叫fragment中的onListItemClick()方法,接著在呼叫onArticleSelected()方法與Activity分享事件。


public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Append the clicked item's row ID with the content provider Uri
        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        mListener.onArticleSelected(noteUri);
    }
    ...
}

傳入onListItemClick()方法中的id參數是被選的項目行ID,id用來從activity的ContentProvider取文章。

4 則留言:

  1. 您好,請問如何在一個fragment中按一個按鈕切換到一個新的activity頁面呢?

    回覆刪除
    回覆
    1. Hi HSP

      在fragment中切換到另一個頁面的方式很多,這裡提供一個以較直覺的方式。
      在按鈕上設置OnClickListener監聽click事件,接著當click事件發生時,利用getActivity()取得fragment目前相連結的Activity,利用activity呼叫startActivity(Intent intent)進行切換。

      刪除
  2. 能不能解說一下,從MainActivity按下按鈕,
    刷新嵌在MainActivity內的Fragment畫面,
    這要怎麼做,一定要實作介面嗎?

    因為你這個例子是Activity裡的FargmentA到同一個Activity裡的FargmentB,
    我想做的是Activity直接到Activity裡的Fragment,
    有點看不太懂QQ



    回覆刪除
    回覆
    1. Hi 張維棟
      依我了解,你是希望達成在Activity中某一事件被觸發後更新Fragment的畫面。
      可以嘗試在Fragment中提供一個方法給Activity呼叫,如下

      public class MyFragment extends Fragment {

      public void refreshUi(){
      getActivity().runOnUiThread(new Runnable(){
      @Override
      public void run(){
      // 刷新介面元件
      }
      });
      }

      }

      刪除