Pages

Thursday, April 17, 2014

Fragment trong Android

Fragment


Một Fragment đại diện cho một hành vi hoặc một phần của user interface trong một activity.
  Bạn có thể kết hợp nhiều fragments trong một activity để xây dựng một multi-panen (đa khung)  UI và sử dụng lại một fragment trong nhiều activity. Bạn có thể nói một fagment như một  phần modular của   một activity.
  - Fragment có lifecycle riêng, nhận sự kiện input riêng của nó.
  - Fragment có thể thêm hoặc xóa khi activity đang chạy.
  - Fragment phải luôn luôn được nhúng trong activity. Vòng đời của fragment bị ảnh hưởng trực tiếp bởi vòng đời chủ của activity. Cho ví dụ:
   + Khi một activity dừng lại , tất cả các fragment trong nó đều dừng lại.
   + Khi một activity bị hủy, tất cả các fragment đều bị hủy.
  - Trong khi activity đang chạy( trong trạng thái resumed ), chúng ta có thể thao tác mỗi fragment một cách không phụ thuộc chẳng hạn như thêm và xóa các fragment.
 - Khi thực hiện chẳng hạn như một transaction của fragment bạn cũng có thể thêm nó vào back stack được quản lý bởi activity - mỗi hạng mục back stack  trong activity là một record của fragment transaction đã xảy ra. Back stack cho phép user đảo ngược một fragment transaction, tức là navigate backward, bởi việc bấm nút Back.
    ---------------------------------------------------------------------------------------
  - Khi ta thêm một fragment như là một phần layout của activity chúng ta, nó tồn tại trong ViewGroup
    bên trong cấp bật view của activity và fragment sẽ định nghĩa layout riêng của nó.
  - Chúng ta có thể insert một fragment vào activity layout bằng cách khai báo một fragment
    trong layout của activity, như là phần tử <fragment>, hoặc từ code của ứng dụng bằng cách add nó vào
    một GroupView đang tồn tại.
  - Một fragment không nhất thiết là một phần của activity layout; bạn cũng có thể sử dụng một fragment
    mà không có giao diện riêng của nó ( layout ) như là một phần hoạt động vô hình của activity.
    ---------------------------------------------------------------------------------------
    Design Philosophy: Triết lý thiêt kế
    Android giới thiệu fragment trong Android 3.0(API 11), chủ yếu để hổ trợ dynamic và flexible thiết kế         trên màn hình rộng ( large screens ), chẳng hạn như tablets. bởi vì màn hình của tablet lớn hơn nhiều               handset, có nhiều chỗ combine và thay thế những thành phần UI với nhau. Fragment cho phép bạn thiết kế     như vậy mà không cần thay đổi phức tạp tới hện thống phân cấp view. Bởi việc chia layout của một               activity thành những fragment, bạn có thể thay đổi sự xuất hiện của activity tại thời điển runtime(đang chạy ) và bảo lưu những thay đổi trong back stack được quản lý bởi activity.
    Cho ví dụ, một ứng dụng mới có thể sử dụng một fragment show một list của các article phía bên trái
    và một fragment display một ariticle phía bên phải - cả 2 fragments trong một activity,nằm cạnh nhau,
    mỗi một fragment có riêng các phương thức lifecycle callback và xử lý những user input events của chúng.
    Vì thế,  thay vì sử dụng một activity để select một article và một activity khác để đọc article, người dùng
    có thể chọn article và đọc nó tất cả bên trong một activity, as illustrated in the tablet layout in figure 1:
    ----------------------------------------------------------------------------------------
    Bạn nên thiết kế mỗi fragment như một modular và một thành phần của activity có thể sử dụng lại.
    Đó là, bở vì mỗi fragment định nghĩa layout cho riêng nó và những hành vi cho riêng nó và
    những callback lifecycle cho riêng nó, bạn có thể dùng một fragment trên nhiều activity, vì thế bạn
    nên thiết kế để sử dụng lại và bỏ qua việc điều khiển một fragment từ một fragment khác. Đây là điều
    đặc biệt quang trọng bởi vì một moduler fragment cho phép bạn thay đổi fragment của bạn kết hợp với
    những kích cở màn hình khác nhau. Khi thiết kế ứng dụng bạn để hổ trợ cả tablets và handset, bạn có thể
    sử dụng lại fragment của bạn trong nhiều cấu hình layout khác nhau để tối ưu kinh nghiệm người dùng  dựa trên  những không gian màn hình khả dụng. Cho ví dụ, trên một thiết hị handset, nó có thể cần thiết để tách
    biệt các fragment để cung cấp một single-pane UI khi nhiều hơn một không thể lấp vừa đủ vào một
    activity có không gian chật hẹp :
    ----------------------------------------------------------------------------------------
    Cho ví dụ,  ứng dụng có thể nhúng 2 fragments trong activity A
    khi chạy trên một thiết bị tablet-sized. Tuy nhiên, trên một màn hình handset-sized, không có đủ chỗ
    cho cả 2 fragment, vì thế Activity A sẽ bao gồm chỉ một Fragment cho list của các article, và khi
    người dùng select một article, nó chạy activity B,cái mà bao gồm fragment thứ 2 để đọc article. Do đó,
    ứng dụng có thể hổ trợ cả tablet và handset thì phải sử dụng lại những fragment trong các combinations
    khác nhau, như đã chứng minh ở  figure 1.

    Để có nhiều thông tin về thiết kế ứng dụng của bạn với các fragment khác nhau kết hợp với nhiều cầu hình
    màn hình khác nhau , xem hướng dẫn : http://developer.android.com/guide/practices/tablets-and-handsets.html
 
Tạo một Fragment 
 
    Để tạo một fragment,bạn phải tạo một Subclass của lớp Fragment (hoặc một subclass của nó).
    Fragment class có code phần nhiều trông giống như của một Activity. Nó chứa những phương thức
    callback tương tự như của activity, như là onCreate() onStart(), onPause(), và onStop().
    Trong thực tế, nếu bạn convert một ứng dụng android sang để sử dụng fragment, bạn có thể chỉ đưng giản
    di chuyển code nhưng phương thức callback của các activity sang riêng từng phương thức callback của fragment.
 
     - Thông thường, bạn nên thi hành ít nhất những phương thức callback sau:
     onCreate()
      Hệ thống gọi phương thức nay khi đang tạo fragment. Bên trong thực thi của bạn, bạn nên khởi tạo
      những thành phần cốt yếu của fragment mà bạn muốn giử lại khi fragment dừng(paused) hoặc stoped,
      hoặc resumed.
     onCreateView()
      Hệ thống sẽ gọi hàm này khi nó dành thời gian cho việc vẽ giao diện người dùng cho lần đầu tiên
      Để vẻ một UI cho fragment của bạn bạn phải return một view từ phương thức này mà đó là root của
      layout của fragment. Bạn có thể return null nếu fragment không cung cấp một UI nào cả.
     onPause()
      hệ thống gọi phương thức này khi sự biểu thị đầu tiên chi ra rằng user đang rời khỏi fragment(mặc dầu vậy nó không luôn luôn có nghĩa là fragment đang bị destroyed). Đây là thông thường nơi mà bạn nên
      commit bất kỳ thay đổi nào mà còn duy trì cho session hiện tại của user cho sau này.
      (Bởi vì user có thể không quay trở lại ).
   
     Hầu hết các ứng dụng nên thực thi ít nhất 3 phương thức đó cho mỗi fragment,nhưng có vài phương thức
     callback khác cũng nên sử dụng để xử lý những giai đoạn khác nhau của fragment lifecycle.
     tất cả các phương thức lifecycle callback được thảo luận trong:
     ------------------------------------------------------------------------------
     Cũng có vài subclass mà bạn muốn mở rộng, thay vì lớp Fragment cơ bản:
   
     DialogFragment
      Hiển thị một hộp thoại nỗi.Việc sử dụng lớp này để tạo một dialog là một thay thế tốt
      để sử dụng những phương thức hổ trợ dialog trong lớp Activity, bởi vì bạn có thể sát nhập
      một fragment dialog vào backstack của các fragment quản lý bởi activity, cho phép user
      có thể return lại một dismissed fragment.
     ListFragment
      Hiển thị một list items được quản lý bởi một adapter(Chẳng hạn như một SimpleCursorAdapter)
      tương tự với ListActivity.Nó cung cấp vài phương thức để quản lý một list view, chẳng hạn như
      onListItemClick() callback để xử lý những sự kiến click.
   
     PrefrenceFragment
      Hiển thị hệ thông cấp bật của đối tượng Preference như là một list, tương tự như PreferenceActivity.
      Điều nay hữu dụng khi tạo một "setting" activity cho ứng dụng của bạn.

    Thêm một user interface 

     Một fragment luôn luôn được sử dụng như một phần user interface của activity và đóng góp layout của
     nó vào Activity.
   
     Để cung cấp một layout cho một fragment, bạn phải thực thi trên phương thức callback onCreateView()
     cái mà hệ thống Android gọi tại thời điểm fragment vẽ layout của nó.
     Khi bạn thực thi phương thức này bạn phải retrun lại một view mà đó là root layout của fragment.
   
     ||Note: Nếu fragment của bạn là một lớp con của ListFragment,mặc định sẽ return lại ListView từ
     ||onCreateView(), vì thế bạn không cần thực thi nó.
   
     Để return một layout từ onCreateView(), bạn có thể inflate nó từ một layout resource đã định nghĩa
     trong XML.Để giúp đở bạn làm được như thế, onCreateView() cung cấp một LayoutInflater object.
   
     Cho ví dụ, dưới đây là một subclass của Fragment nó load một layout từ example_fragment.xml file:
   
     public static class ExampleFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}
     Tham số container được chuyển tới onCreateView() là parent ViewGroup(từ layout của activity)
     trong cái fragment layout sẽ được insert.The tham số savedInstanceState là một Bundle mà cung cấp
     dữ liệu về các thể trước đó của fragment, nếu fragment đang được resumed(việc phục hồi trạng thái
     được thảo luần nhiều trong mục : http://developer.android.com/guide/components/fragments.html#Lifecycle)
   
     Phương thức inflate() lấy 3 đối số:
     - resource ID của layout bạn muốn inflate
     - ViewGroup là cha của inflate layout. Việc chuyển containor là quang trọng để cho hệ thống
     cung cấp những tham số layout tới root view của inflate layout, chỉ định bởi parent view
     trong cái mà nó sẽ làm...
     - Một boolean chỉ ra rằng có hay không một layout đã inflate nên đính kèm vào ViewGroup(tham số thứ 2)
     suốt quá trình inflate.(trong trường hợp này,cái này false bởi vì hệ thống đã insert 
     layout vào containor - nếu chuyển true sẽ tạo dư thừa view group trong final layout.)
   
     Bây giờ bạn đã thấy thế nào để tạp một fragment mà cung cấp một layout.Tiếp theo bạn cần thêm
     một fragment vào activity của bạn.
    
Thêm một fragment vào activity 

     Thông thường, một fragment góp phần tới giao diện của activity chủ, cái mà được nhúng như
     một phần phân cấp view của activity. Có 2 cách có thể thêm fragment đến activity layout:
   
     - Khai báo fragment bên  trong file layout của activity.
     - Add Fragment vào một ViewGroup đag tồn tại.
      Tại thời điểm activity đang chạy, bạn có thể add một fragment vào activity layout của bạn.
       đơn giản là chỉ định ViewGroup để đặt fragment của bạn.
      Để tạo một fragment transaction trong activity của bạn( chẳng hạn như add, remove hoặc thay thế
       một fragment ) bạn phải sử dụng APIs từ lớp FragmentTransaction. Bạn có thể lấy một cá thể
       của lớp FragmentTransaction từ Activity của bạn như sau :
       ------------------------------------------------------------------
       | FragmentManager fragmentManager = getFragmentManager()
| FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
     ------------------------------------------------------------------
      Bạn có thể add một fragment sử dụng phương thức add(),chỉ định fragment và view để add.
      ví dụ như :
       ------------------------------------------------------------------
       | ExampleFragment fragment = new ExampleFragment();
| fragmentTransaction.add(R.id.fragment_container, fragment);
| fragmentTransaction.commit();
Tham số đầu tiên chuyển tới add() là ViewGroup để lưu trử fragment,được chỉ định bởi ID từ
resource, tham số thứ 2 là fragment.
Kể từ khi bạn đã tạo sự thay đổi với lớp FragmentTracsaction, bạn phải gọi commit() để
có hiệu lực.
------------------------------------------------------------------
------------------------------------------------------------
Adding a fragment without a UI (Thêm một fragment không có UI)
------------------------------------------------------------
Bạn có thể sử dụng fragment để cung cấp một xử lý nền (background) cho activity mà không
hiển thị một giao diện UI.
Để add một fragment mà không có UI, add fragment từ activity sử dụng add(Fragment, String)
(cung cấp một string "tag" duy nhất cho fragment, chứ không phải là view ID). Cách này sẽ
add một fragment, nhưng mà, bởi vì nó không được liên kết với với một view trong acvtivity layout,
nó sẽ không nhận cuộc gọi  từ onCreateView(). Vì thế bạn không cần thực thi phương thức đó.
Việc cung cấp một string tag cho fragment của bạn nó không nghiêm ngặt cho fragment không có UI
bạn cũng có thể cung cấp những string tag cho fragment có UI - nhưng nếu fragment không có UI
dó đó string tag là cách duy nhất để nhận ra nó.Nếu bạn muốn lấy lại fragment từ activity sau đó
bạn cần sử dụng findFragmentByTag().
Cho một ví dụ activity sử dụng fragment như một bacground worker, không có UI,xem :
ví dụ http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentRetainInstance.html
----------------------------------------------------------------------------------------
Managing Fragments ( Quản lý Fragments )
----------------------------------------------------------------------------------------
Để quản lý fragment trong activity của bạn , bạn cần sử dụng FragmentManager. Để có được nó,
gọi getFragmentManager() từ activity của bạn.
Với Fragment bạn có thể làm :
- Có thể lấy những fragment đang tồn tại trọng activity, bằng findFragmentById() (đối với
những fragment cũng cấp UI trong activity layout) hoặc là findFragmentByTag() - cho những
fragment không cung cấp UI.
- Lấy fragments khỏi stack bằng popBackStatck() - Tương tự câu lệnh Back bởi user.
- Đăng ký sự kiện lắng nghe cho sự thay đổi của back stack, với addOnbackStackChangedListener().
---------------------------------------------------------------------------
Performing Fragment Transactions ( Thực hiện Fragment Transactions )
---------------------------------------------------------------------------
Một đặc tính đang chú ý về việc sử dụng các fragment trong activity là việc code thể add,
remove , replace và thực thi các thao tác khác với chúng, để đáp ứng với tương tác của người dùng
Với một loạt các thay đổi mà bạn commit tới activity được gọi bởi một transaction và bạn có
thể thực thi chúng bằng cách sử dụng các API trong FragmentTransaction. Bạn cũng có thể lưu mỗi
transaction vào một back stack được quản lý bởi activity, cho phép user navigate back thông qua
những thay đổi của các fragment( tương tự như navigate back thông qua các activitys).
Bạn có thể thu được một cá thể của FragmentTransaction từ FragmentManager như sau:
---------------------------------------------------------------------------
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
---------------------------------------------------------------------------
Mỗi một transaction là một tập các thay đổi mà bạn muốn thực thi tại một thời điểm.
Bạn có thể thiết lập tất cả các sự thay đổi cho một transaction sử dụng những phương
thức :
- add();
- remove();
- replace();
sau đó để cung cấp transaction tới Activitys, bạn phải gọi commit().
Trước khi gọi commit(), bạn có thể gọi addTobackStack(), để thêm transaction vào back stack.
back stack này được quản lý bởi activity và cho phép user quay trở lại những trạng thái fragment
trước đó, bằng cách bấm nút Back.
Cho ví dụ :
---------------------------------------------------------------------------------
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
---------------------------------------------------------------------------------
Còn tiếp .....