【Android 应用开发】 Fragment 详解
作者 : 韓曙亮
轉載請著名出處 :?http://blog.csdn.net/shulianghan/article/details/38064191
本博客代碼地址 :?
-- 單一 Fragment 示例 :?https://github.com/han1202012/Octopus-Fragement.git
-- 可復用的 Fragment 示例 :?https://github.com/han1202012/Octopus-Fragement_TwoModel.git
.
Fragment 總結?
(1)?
.
1. Fragement 概述
Fragement 與 Activity 生命周期關系?: Fragement 嵌入到 Activity 組件中才可以使用, 其生命周期與 Activity 生命周期相關.
-- stop 與 destroy 狀態 : Activity 暫停 或者 銷毀的時候, 其內部嵌入的所有的 Fragement 也會執行 暫停 或者 銷毀 操作;
-- 活動狀態 : 只有當 Activity 處于活動狀態的時候, 我們才能操作 Fragement;
Fragement 特征 :?
-- Fragement 與 Activity 交互 : Fragement 調用 getActivity() 獲取其 所嵌入的 Activity, Activity 獲取 FragementManager 的findFragementById() 或 findFragementByTag() 獲取 Fragement;
-- Activity 增刪 Fragement : Activity 調用 Fragement 的 add(), remove(), replace() 等方法 添加 刪除 替換 Fragement;
-- Fragement 與 Activity 對應關系 : 一個 Activity 中可以嵌入多個 Fragement, 一個 Fragement 可以嵌入多個 Activity;
-- 生命周期受 Activity 影響 : Fragement 的生命周期 受 Activity 生命周期控制;
Fragement 作用 :??Fragement 是為了 Android 中 平臺電腦 UI 設計, 開發者不用設計 非常負責的 界面, 只需要設計好模塊, 對UI 組件進行 分組 和 模塊化的設計和開發, 簡化了 UI 組件;
Fragement 可復用性 : 同一個 app 應用, 可以在不同的 Activity 中加載同一個 Fragement;
2. Fragement 類 和 方法介紹
(1) Fragement 相關類介紹
Fragement 子類 :?
-- DialogFragement : 對話框界面的 Fragement, 顯示一個浮動的對話框, 這個對話框可以方便的與 Activity 進行交互, Activity 可以管理這個 Fragment;
-- ListFragement : 列表界面的 Fragement, 顯示一個條目列表, 該列表可以設置一個適配器, 提供了許多管理 列表的函數;
-- PerformanceFragement : 選項設置界面的 Fragement, 該Fragment 創建 類似與 設置 應用程序時很管用;
-- WebViewFragement : WebView 界面的 Fragement;
(2) Fragement 生命周期相關方法介紹?
onCreate() :
onCreate(Bundle savedInstanceState)
-- 回調時機 : 在創建 Fragement 的時候回調;
-- 參數解析 : Bundle savedInstance, 用于保存 Fragment 參數, Fragement 也可以 重寫?onSaveInstanceState(Bundle outState) 方法, 保存Fragement狀態;
-- 執行的動作 : 獲取 Frgement 顯示的內容, 以及啟動Fragment 傳入的參數, 調用 getArguments() 獲取鍵值對;
onCreateView() :?
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);-- 回調時機 : Fragement 繪制界面組件?的時候回調, 該方法返回 View, 這個View就是 Fragement 本身;
-- 參數解析 : inflater 布局加載器, 是上下文傳入, 不用自己創建; container 加載組件的父容器;
-- 執行的操作 : 使用 inflate 布局加載器 加載布局文件, 并未組件設置顯示的值;
onPause() :?
-- 回調時機 : Fragement 暫停的時候, 即進入后臺的時候 回調;
3. Fragment 創建
Fragment 創建 :?
-- 參數準備 : 創建一個 Bundle 對象, 并向其中設置參數 :?
Bundle bundle = new Bundle(); bundle.putString("key", "value"); -- 創建 Fragment 對象 : 使用 new MyFragment() 創建對象, 并 調用 myFragment.setArguments(bundle) ?方法傳入參數; MyFragment myFragment = new MyFragment(); myFragment.setArguments(bundle);Fragment嵌入Activity方式?: Fragment 添加到 Activity 中才能顯示, 以下是將 Fragment 嵌入 Activity 的方式;
--?布局文件嵌入?: 在布局文件中 使用 <Fragment /> 元素, 通過定義?android:name = "com.example.MyFragment"?屬性指定 Fragment 類;
--?代碼方式嵌入?: 調用 FragmentTransaction 對象的 add() 方法向 Activity 中添加 Fragment;
4. Fragment 與 Activity 通信
Fragment 獲取 Activity : 調用 Fragment 對象的 getActivity()方法, 即可獲取 Fragment 嵌入的 Activity 對象;
Activity 獲取 Fragment :?
-- Fragment 屬性 : 在布局文件中, 可以為 <Fragment /> 元素指定 android:id 和 android:tag 屬性;
-- 獲取方法 : 調用 Activity 的 findFragmentById(int id) 或者 findFragmentByTag(String tag)方法;
Fragment 向 Activity 傳遞數據 : 將 Activity 當作接口子類對象, Fragment 中調用 Activity 中的接口方法;
-- Fragment 定義接口 : 在 Fragment 內部定義一個 Callback 接口;
-- Activity 實現該接口 : MyActivity extends Activity implement MyFragment.Callback;
-- Fragment 中獲取該接口對象 : 在Fragment 中定義一個 Callback 全局變量, 然后在 onAttach(Activity activity) 方法中, 將 activity 強轉為 Callback 對象;?
-- 調用接口方法 : 上面獲取了 Callback 對象, 即Activity對象, 調用 Activity 中的 接口方法, 就能在 Fragment 中調用 Activity 對應的方法了;
Activity 向 Fragment 傳遞數據 :?
-- 創建 Bundle 數據包 : 創建一個 Bundle 對象, 把要存放的鍵值對 放到這個對象中;
-- 設置 Bundle 對象給 Fragment : 調用 Fragment 對象的 setArguments(Bundle bundle) 方法, 將 Bundle 對象設置給 Fragment;
5. Fragment 事務管理
FragmentManager 功能 : FragmentManager 對象 可以通過 activity.getFragmentManager()獲取;
-- 獲取指定 Fragment : 通過 findFragmentById() 或者 findFragmentByTag() 方法獲取指定 Fragment;
-- 彈出棧 : 通過調用 popBackStack(), 將 Fragment 從后臺的 棧 中彈出;
-- 監聽棧 : 通過調用 addOnBackStackChangeListener 注冊監聽器, 監聽 后臺棧變化;?
FragmentTransaction 對象獲取途徑?:?
--?獲取 FragmentManager 對象?: 調用 Activity 的?getFragmentManager()?獲取 FragmentManager 對象;
--?獲取 FragmentTansaction 對象?: 調用 FragmentManager 對象的?beginTransaction()?方法獲取 FragmentTransaction 對象;
FragmentTransaction(Fragment 事務)作用 : 對 Fragement 進行 增, 刪 , 改 操作需要 FragmentTransaction 對象進行操作, 開啟 這個事務, 獲取 事務對象, 然后執行對 Fragment 的操作, 最后提交事務;
-- 開啟事務 : ?調用 Fragement 對象的 beginTransaction() 方法可以獲取 FragementTransaction 對象;
-- 操作碎片 : ?FragmentTransaction 對象 中 包含了 add(), remove(), replace() 等方法;
-- 提交操作 : ?當執行完 Fragement 的操作之后, 可以調用 FragementTransaction 對象的 commit() 方法提交修改;
addToBackStack()方法作用 : 該方法是 FragementTransaction 的方法, 在提交事務前調用該方法, 可以將 事務中執行的操作 添加到 back 棧中, 用戶按下 回退鍵, 修改過的 Fragement 會 回退到 事務執行之前的狀態;
6. Fragment 生命周期
(1) Fragment 狀態
活動狀態 : Fragment 處于前臺, 可見, 可以獲取焦點;
暫停狀態 : Fragment 嵌入的Activity 也處于暫停狀態, 即 Fragment 處于后臺, 可見, 失去焦點;?
停止狀態 : Fragement 嵌入的 Activity 處于停止狀態, 不可見, 失去焦點;
銷毀狀態 : Fragement 所在的 Activity 被銷毀, 執行了 onDestroy() 方法, 此時 Fragement 被完全刪除;
(2) Fragement 生命周期相關方法
紅色方法 與 Activity 相對應, 藍色方法 是 自身對應的方法, 棕色方法?單獨對應;
onAttach() : 嵌入, Fragement 被嵌入到 Activity 時回調該方法, 只會調用一次;
onCreate() : 創建, Fragement 創建的時候回調該方法, 只會回調一次;
onCreateView() : 繪制, 在 Fragement 繪制的時候回調該方法, 該方法會返回 繪制的 View 組件;
onActivityCreated() : 界面創建, Fragement 所嵌入的 Activity 創建完成回調該方法;
onStart() : 啟動, Fragement 啟動時回調, 此時Fragement可見;
onResume() : 激活, Fragement 進入前臺, 可獲取焦點時激活;
onPause() : 暫停, Fragement 進入后臺, 不可獲取焦點時激活;
onStop() : 停止, Fragement 不可見時回調;
onDestroyView() : 銷毀組件, 銷毀 Fragement 繪制的 View 組件時回調;
onDestroy() : 銷毀, 銷毀 Fragement 回調;
onDetach() : 移除, Fragement 從 Activity 中移除的時候回調;
7. 代碼示例?
(1) 需求分析
縱向手機屏幕 : 兩個界面, 每個界面都有一個 Fragement, ?一個Fragement顯示新聞列表, 一個Fragement 顯示新聞內容;
橫向手機屏幕 : 一個界面, 兩個Fragement, Fragement 顯示內容與上面相同;
(2) 新聞標題 Fragment
存放新聞標題的 Fragment :?NewsTittleFragment.java
package cn.org.octopus;import android.app.Activity; import android.app.ListFragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.ListView;/*** 內部類 : * Callbacks接口* Fragement中維護該接口子類對象 * 需要Activity實現該接口, 實現接口方法 * Activity 在onAttach()方法中傳入; * * 方法簡介 : * 重寫生命周期的 11 個方法;* onAttach() 方法中, 傳入所嵌入的Activity, 并判斷是否嵌入正確* onCreate() 方法中, 創建 Fragement 中 ListView 的適配器, 并將適配器設置給 ListView* onDetach() 方法中, 將 Callbacks 接口子類對象置空** setChoiceMode() 設置ListView 的選擇模式* onListItemClick() ListView 的點擊回調方法* 注意 Android * */ public class NewsTittleFragment extends ListFragment {private Callbacks activityCallback; /* 從 onAttach()方法中傳入的 Callbacks 接口子類, 由 Activity 強制轉換而來 *//** 定義回調接口 * 接口用法 : * 1. 該 Fragement 所 Activity 實現該接口* 2. 該 Fragement 中 維護一個 該接口子類, 即 Activity* 3. 調用 Activity 接口子類的方法, 將數據傳遞給 Activity **/public interface Callbacks{public void onNewsSelect(int id);}/** Fragment 嵌入Activity */@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);System.out.println("onAttach");if ( ! ( activity instanceof Callbacks))System.out.println("Fragement in wrong Activity !");/* 為Activity中定義的Callbacks接口子類對象賦值 */activityCallback = (Callbacks) activity;}/** Fragement 創建* 進行設置適配器操作 */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);System.out.println("onCreate");/* 為 ListFragment 創建適配器* 注意使用的是 Android 自帶的布局, 在 sdk\platforms\android-10\data\res\layout 目錄下* */ListAdapter adapter = new ArrayAdapter<News>(getActivity(), android.R.layout.simple_list_item_activated_1, android.R.id.text1, NewsContent.getInstance().news);/* 設置適配器 給 ListFragement */setListAdapter(adapter);}/** Fragment 繪制 */@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {System.out.println("onCreateView");return super.onCreateView(inflater, container, savedInstanceState);}/** Activity 創建完畢 */@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);System.out.println("onActivityCreated");}/** Fragement 進入可視狀態 */@Overridepublic void onStart() {super.onStart();System.out.println("onStart");}/** Fragement 進入激活狀態 */@Overridepublic void onResume() {super.onResume();System.out.println("onResume");}/** Fragement 進入暫停狀態 */@Overridepublic void onPause() {super.onPause();System.out.println("onPause");}/** Fragement 進入停止狀態 */@Overridepublic void onStop() {super.onStop();System.out.println("onStop");}/** 銷毀 Fragement 顯示組件 */@Overridepublic void onDestroyView() {super.onDestroyView();System.out.println("onDestroyView");}/** 銷毀 Fragement */@Overridepublic void onDestroy() {super.onDestroy();System.out.println("onDestroy");}/** 將 Fragement 從 Activity 中刪除 */@Overridepublic void onDetach() {super.onDetach();System.out.println("onDetach");activityCallback = null;}/*** 列表對象被點擊之后回調的方法*/@Overridepublic void onListItemClick(ListView l, View v, int position, long id) {super.onListItemClick(l, v, position, id);activityCallback.onNewsSelect((int) id);}/** 設定選擇模式, 該列表默認不能選擇, 可以設置為不能選擇, 單選 和 多選* ListView.CHOICE_MODE_NONE 不能選擇* ListView.CHOICE_MODE_SINGLE 單選* ListView.CHOICE_MODE_MULTIPLE 多選* */public void setChoiceMode(int choiceMode) {getListView().setChoiceMode(choiceMode);}}
(3) 新聞內容的 Fragment
存放新聞內容的 Fragment :?NewsContentFragement.java;
package cn.org.octopus;import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView;public class NewsContentFragement extends Fragment {/* Bundle的key */public static final String TAG_NEWS_ID = "cn.org.octopus.news.tittle";private News news;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);/* 校驗 參數中是否包含 TAG_NEWS_ID 鍵值*/boolean isIllegal = getArguments().containsKey(TAG_NEWS_ID);if(isIllegal){/* 如果包含 TAG_NEWS_ID 鍵值, 就會去鍵對應的 id */int id = getArguments().getInt(TAG_NEWS_ID);/* 從 NewsContent 單例對象中的 map 集合中獲取 news 對象 */news = NewsContent.getInstance().news_map.get(id);}}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {/* 加載布局文件 */View rootView = inflater.inflate(R.layout.fragment_news_content, container, false);/* 獲取新聞標題組件 */TextView news_content_tittle = (TextView) rootView.findViewById(R.id.news_content_tittle);/* 獲取新聞內容組件 */TextView news_content_content = (TextView) rootView.findViewById(R.id.news_content_content);if(null != news){/* 設置新聞標題 */news_content_tittle.setText(news.getTittle());/* 設置新聞內容 */news_content_content.setText(news.getContent());}return rootView;}}
(4) 新聞內容存儲相關代碼
新聞實體類 :?
package cn.org.octopus;public class News {private int id; //新聞序號private String tittle; //新聞標題private String content; //新聞內容/** 構造方法 */public News(int id, String tittle, String content) {super();this.id = id;this.tittle = tittle;this.content = content;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getTittle() {return tittle;}public void setTittle(String tittle) {this.tittle = tittle;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}/* 這里只返回標題, 是為了適配 ListFragement 時使用 */@Overridepublic String toString() { // return "News [id=" + id + ", tittle=" + tittle + ", content=" + content // + "]";return tittle;}}
新聞數據 :?
package cn.org.octopus;import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;public class NewsContent {/* 單例模式* 1. 私有 靜態 本類成員變量* 2. 私有 構造 函數* 3. 公共 靜態 函數, 檢查本類成員變量是否為null, 返回本類成員變量 */private static NewsContent newsContent;public List<News> news;public Map<Integer, News> news_map;private NewsContent(){news = new ArrayList<News>();news_map = new HashMap<Integer, News>();News news1 = new News(0, "郭振璽斂財術", "7月30日,央視紀錄頻道CCTV-9總監劉文被帶走。據相關報道,劉文被帶走的原因是 “發現在紀錄片對外采購上有財務問題”,另外,在一些高收視率的紀錄片創作上,“涉嫌與隱性的植入廣告有關的利益交換”。");News news2 = new News(1, "朝鮮新版5000朝元新鈔無金日成頭像", "韓國網刊《每日朝鮮》8月1日報道,已經開始流通的5000朝元新鈔并未印金日成肖像,意味金日成肖像已從朝鮮貨幣上暫時消失。 舊版朝鮮5000元紙幣上印有金日成頭像。");News news3 = new News(2, "美國醫生感染埃博拉", "菲律賓衛生部部長恩里克·奧尼亞說,目前菲律賓尚無埃博拉疫情。衛生部已通報地方衛生部門,一旦發現返菲海外勞工出現感染埃博拉病毒早期癥狀,立即對患者實行隔離治療。衛生部還要求近期即將從海外回國的勞工如出現發燒、頭痛、關節和肌肉疼痛、喉嚨痛等癥狀,在回國前應獲得所雇傭國家衛生部門的無感染證明,以避免埃博拉病毒傳入菲律賓。");news.add(news1);news.add(news2);news.add(news3);news_map.put(news1.getId(), news1);news_map.put(news2.getId(), news2);news_map.put(news3.getId(), news3);}/*** 判斷成員變量 是否為null * 如果不為null, 直接返回;* 如果為null, 先創建在返回;*/public static NewsContent getInstance() {if(newsContent != null)return newsContent;elsereturn new NewsContent();}}
(5) 主界面 Actiity 代碼
主界面代碼 : MainActivity.java
package cn.org.octopus;import android.app.Activity; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; import cn.org.octopus.NewsTittleFragment.Callbacks;public class MainActivity extends Activity implements Callbacks {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);/* 加載布局文件, 這個布局文件中有一個 Fragment, 會自動加載該 Fragmet */setContentView(R.layout.activity_main);}/** * 實現的 Callbasks 接口的方法, * 當 NewsTittleFragement 中的 ListView 被點擊的時候 回調 * */@Overridepublic void onNewsSelect(int id) {/* 創建 Bundle 對象, Activity 傳遞給 Fragment 的參數需要靠該對象進行傳遞 */Bundle arguments = new Bundle();/* 封裝數據到 Bundle 對象中, 注意提前定義好鍵值 */arguments.putInt(NewsContentFragement.TAG_NEWS_ID, id);/* 創建 Fragment 對象 */NewsContentFragement fragement = new NewsContentFragement();/* 將 Activity 要傳遞的數據 傳遞給 Fragment 對象 */fragement.setArguments(arguments);/* 獲取FragmentManager 對象 */FragmentManager manager = getFragmentManager();/* 開啟事務, 獲取事務 */FragmentTransaction transaction = manager.beginTransaction();/* 在事務中進行替換操作 */transaction.replace(R.id.news_content, fragement);/* 提交操作 */transaction.commit();}}
(6) AndroidManifest.xml 配置文件
(7) 執行結果
跟蹤的 Fragment 生命周期回調函數打印的結果 :?
I/System.out( 8604): onAttach I/System.out( 8604): onCreate I/System.out( 8604): onCreateView I/System.out( 8604): onActivityCreated I/System.out( 8604): onStart I/System.out( 8604): onResume I/System.out( 8604): onPause I/System.out( 8604): onStop I/System.out( 8604): onDestroyView I/System.out( 8604): onDestroy I/System.out( 8604): onDetach
界面執行結果 :?
.
8. 出錯處理
(1) 引用 不用包中的 Fragment
引用?android.app.ListFragment, 不會出現錯誤, 而 引用?android.support.v4.app.ListFragment?類會出現如下錯誤;
錯誤 :?
08-06 22:17:12.537: E/AndroidRuntime(3751): FATAL EXCEPTION: main 08-06 22:17:12.537: E/AndroidRuntime(3751): java.lang.RuntimeException: Unable to start activity ComponentInfo{cn.org.octopus/cn.org.octopus.MainActivity}: android.view.InflateException: Binary XML file line #11: Error inflating class fragment 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2255) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2309) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.ActivityThread.access$700(ActivityThread.java:157) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1289) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.os.Handler.dispatchMessage(Handler.java:99) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.os.Looper.loop(Looper.java:176) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.ActivityThread.main(ActivityThread.java:5319) 08-06 22:17:12.537: E/AndroidRuntime(3751): at java.lang.reflect.Method.invokeNative(Native Method) 08-06 22:17:12.537: E/AndroidRuntime(3751): at java.lang.reflect.Method.invoke(Method.java:511) 08-06 22:17:12.537: E/AndroidRuntime(3751): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102) 08-06 22:17:12.537: E/AndroidRuntime(3751): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869) 08-06 22:17:12.537: E/AndroidRuntime(3751): at dalvik.system.NativeStart.main(Native Method) 08-06 22:17:12.537: E/AndroidRuntime(3751): Caused by: android.view.InflateException: Binary XML file line #11: Error inflating class fragment 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:710) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.view.LayoutInflater.rInflate(LayoutInflater.java:752) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.view.LayoutInflater.inflate(LayoutInflater.java:495) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.view.LayoutInflater.inflate(LayoutInflater.java:397) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.view.LayoutInflater.inflate(LayoutInflater.java:353) 08-06 22:17:12.537: E/AndroidRuntime(3751): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:360) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.Activity.setContentView(Activity.java:1932) 08-06 22:17:12.537: E/AndroidRuntime(3751): at cn.org.octopus.MainActivity.onCreate(MainActivity.java:13) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.Activity.performCreate(Activity.java:5326) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1097) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2218) 08-06 22:17:12.537: E/AndroidRuntime(3751): ... 11 more 08-06 22:17:12.537: E/AndroidRuntime(3751): Caused by: android.app.Fragment$InstantiationException: Trying to instantiate a class cn.org.octopus.NewsTittleFragment that is not a Fragment 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.Fragment.instantiate(Fragment.java:584) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.Fragment.instantiate(Fragment.java:560) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.app.Activity.onCreateView(Activity.java:4908) 08-06 22:17:12.537: E/AndroidRuntime(3751): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:686) 08-06 22:17:12.537: E/AndroidRuntime(3751): ... 21 more 08-06 22:17:12.537: E/AndroidRuntime(3751): Caused by: java.lang.ClassCastException 08-06 22:17:12.537: E/AndroidRuntime(3751): ... 25 more
(2) ListView 適配器設置錯誤
ListView 適配器引用的 組件, 必須是已經加載過的, 通過 onCreate()中的 setContentView()方法加載, 或者通過 LayoutInflater 進行加載;
錯誤 :?
08-06 22:39:22.139: W/dalvikvm(4413): threadid=1: thread exiting with uncaught exception (group=0x40dc0930) 08-06 22:39:22.139: E/AndroidRuntime(4413): FATAL EXCEPTION: main 08-06 22:39:22.139: E/AndroidRuntime(4413): android.content.res.Resources$NotFoundException: Resource ID #0x7f080001 type #0x12 is not valid 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.content.res.Resources.loadXmlResourceParser(Resources.java:3033) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.content.res.Resources.getLayout(Resources.java:1722) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.LayoutInflater.inflate(LayoutInflater.java:395) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:371) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.ArrayAdapter.getView(ArrayAdapter.java:362) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.AbsListView.obtainView(AbsListView.java:2603) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.ListView.makeAndAddView(ListView.java:1840) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.ListView.fillDown(ListView.java:681) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.ListView.fillFromTop(ListView.java:742) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.ListView.layoutChildren(ListView.java:1661) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.AbsListView.onLayout(AbsListView.java:2426) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.View.layout(View.java:14905) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewGroup.layout(ViewGroup.java:4601) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.FrameLayout.onLayout(FrameLayout.java:448) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.View.layout(View.java:14905) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewGroup.layout(ViewGroup.java:4601) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.FrameLayout.onLayout(FrameLayout.java:448) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.View.layout(View.java:14905) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewGroup.layout(ViewGroup.java:4601) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1021) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.View.layout(View.java:14905) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewGroup.layout(ViewGroup.java:4601) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.FrameLayout.onLayout(FrameLayout.java:448) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.View.layout(View.java:14905) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewGroup.layout(ViewGroup.java:4601) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1694) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1552) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.LinearLayout.onLayout(LinearLayout.java:1465) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.View.layout(View.java:14905) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewGroup.layout(ViewGroup.java:4601) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.widget.FrameLayout.onLayout(FrameLayout.java:448) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.View.layout(View.java:14905) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewGroup.layout(ViewGroup.java:4601) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2213) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2027) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1237) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5162) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.Choreographer.doCallbacks(Choreographer.java:591) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.Choreographer.doFrame(Choreographer.java:561) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.os.Handler.handleCallback(Handler.java:725) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.os.Handler.dispatchMessage(Handler.java:92) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.os.Looper.loop(Looper.java:176) 08-06 22:39:22.139: E/AndroidRuntime(4413): at android.app.ActivityThread.main(ActivityThread.java:5319) 08-06 22:39:22.139: E/AndroidRuntime(4413): at java.lang.reflect.Method.invokeNative(Native Method) 08-06 22:39:22.139: E/AndroidRuntime(4413): at java.lang.reflect.Method.invoke(Method.java:511) 08-06 22:39:22.139: E/AndroidRuntime(4413): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102) 08-06 22:39:22.139: E/AndroidRuntime(4413): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869) 08-06 22:39:22.139: E/AndroidRuntime(4413): at dalvik.system.NativeStart.main(Native Method)
9. Fragement 復用問題
需求 : 在手機豎屏的時候, 新聞列表 和 新聞內容 在兩個 Activity 中, 橫屏的時候, 在一個 Activity 中;
(1) 根據不同的環境加載不同的布局
定義實際引用的資源?: 在 Java 代碼中引用資源的時候, 會到 values 中查詢, 是否有定義資源文件, 如果有, 優先按照該定義加載指定資源文件;
-- 定義方式 : 下面的定義, 如果代碼中引用 R.layout.activity_main, 符合條件的話, 使用 R.layout.activity_main_land?布局文件;
<resources><item type="layout" name="activity_main">@layout/activity_main_land</item> </resources>-- 屬性說明 : type 資源的類型, name 資源名稱;
(2) 判斷加載的布局文件
判斷的依據 : 根據 兩個布局文件的差異, 任意查找一個組件, 或者定義一個 不占位置的組件, 來進行判定;
/* 查看加載的是哪個文件, 如果文件中包含 R.id.news_content_content 組件, 就說明現在是橫屏的 */isLand = findViewById(R.id.news_content) != null;
(3) MainActivity 代碼差異
(4) 新增了?NewsContentActivity?
(5) 新增 或 修改的布局文件
activity_main.xml :?
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" ><fragment android:id="@+id/tittle_fragment"android:name="cn.org.octopus.NewsTittleFragment"android:layout_width="0dp"android:layout_weight="1"android:layout_height="match_parent"/></LinearLayout>activity_main_land.xml :?
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" android:orientation="horizontal"android:divider="?android:attr/dividerHorizontal"android:showDividers="middle"><!--資源引用方式解析 : @+id : 定義一個 id 值, 用于識別組件@id : 引用 id 值代表的組件@anroid:type : 引用 Android 內部的資源, type 指的是 drawable string 等資源類型?android:attr : 引用 Android 內部的樣式分割線解析 : 分割線資源 : 在 android:divider 屬性中引入樣式, 這里通過 ?android:attr 引入一個 android 的自定義樣式分割線樣式 : android:showDivider 屬性中設置, none 不顯示分割線, beginning 在開始處顯示, end 在結尾顯示, middle 中間顯示--><fragment android:id="@+id/tittle_fragment"android:name="cn.org.octopus.NewsTittleFragment"android:layout_width="0dp"android:layout_weight="1"android:layout_height="match_parent"/><FrameLayout android:id="@+id/news_content"android:layout_width="0dp"android:layout_weight="3"android:layout_height="match_parent"/></LinearLayout>
activity_news_content.xml :?
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/news_content"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" />
(6) 執行效果
豎屏 :?
橫屏 :?
作者?:?韓曙亮
轉載請著名出處?:?http://blog.csdn.net/shulianghan/article/details/38064191
總結
以上是生活随笔為你收集整理的【Android 应用开发】 Fragment 详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【iOS 开发】Objective-C
- 下一篇: 【Android 应用开发】Activi