作者 : 韩曙亮

转载请著名出处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 */
	@Override
	public 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 创建
	 * 	进行设置适配器操作 */
	@Override
	public 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 绘制 */
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		System.out.println("onCreateView");
		return super.onCreateView(inflater, container, savedInstanceState);

	}

	/** Activity 创建完毕 */
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		System.out.println("onActivityCreated");
	}

	/** Fragement 进入可视状态 */
	@Override
	public void onStart() {
		super.onStart();
		System.out.println("onStart");
	}

	/** Fragement 进入激活状态 */
	@Override
	public void onResume() {
		super.onResume();
		System.out.println("onResume");
	}

	/** Fragement 进入暂停状态 */
	@Override
	public void onPause() {
		super.onPause();
		System.out.println("onPause");
	}

	/** Fragement 进入停止状态 */
	@Override
	public void onStop() {
		super.onStop();
		System.out.println("onStop");
	}

	/** 销毁 Fragement 显示组件 */
	@Override
	public void onDestroyView() {
		super.onDestroyView();
		System.out.println("onDestroyView");
	}

	/** 销毁 Fragement */
	@Override
	public void onDestroy() {
		super.onDestroy();
		System.out.println("onDestroy");
	}

	/** 将 Fragement 从 Activity 中删除 */
	@Override
	public void onDetach() {
		super.onDetach();
		System.out.println("onDetach");
		activityCallback = null;
	}

	/**
	 * 列表对象被点击之后回调的方法
	 */
	@Override
	public 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;

	@Override
	public 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);
		}
	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
	}

	@Override
	public 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 时使用 */
	@Override
	public 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;
		else
			return 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 {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		/* 加载布局文件, 这个布局文件中有一个 Fragment, 会自动加载该 Fragmet */
		setContentView(R.layout.activity_main);
	}

	/**
	 * 实现的 Callbasks 接口的方法,
	 * 当 NewsTittleFragement 中的 ListView 被点击的时候 回调
	 * */
	@Override
	public 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 配置文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.org.octopus"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <!--
	    	设置屏幕方向 android:screenOrientation :
	    		unspecified : 默认值, 系统自动判定方向
	    		landscape : 横屏显示
	    		portrait : 竖屏显示
	    		user : 用户当前首选方向
	    		behind : 与 之前的 Activity 方向一致;
	    		sensor : 由物理传感器决定
	    		nosenser : 忽略物理传感器感应
	     -->

        <activity
            android:name="cn.org.octopus.MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="landscape">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

(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 代码差异

package cn.org.octopus;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import cn.org.octopus.NewsTittleFragment.Callbacks;

public class MainActivity extends Activity implements Callbacks {

	private boolean isLand;		/* 标识是否是横屏 */

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		/* 加载布局文件, 这个布局文件中有一个 Fragment, 会自动加载该 Fragmet */
		setContentView(R.layout.activity_main);

		/* 查看加载的是哪个文件, 如果文件中包含 R.id.news_content_content 组件, 就说明现在是横屏的 */
		isLand = findViewById(R.id.news_content) != null;
	}

	/**
	 * 实现的 Callbasks 接口的方法,
	 * 当 NewsTittleFragement 中的 ListView 被点击的时候 回调
	 * */
	@Override
	public void onNewsSelect(int id) {

		/* 如果是横屏的情况, 两个 Fragement 都在一个界面中  */
		if(isLand){
			/* 创建 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();
		}else{	/* 竖屏的情况, 需要开启 Activity */
			System.out.println("isLand : " + isLand);
			Intent intent = new Intent(getApplicationContext(), NewsContentActivity.class);
			/* 通过 Intent 的 Bundle 对象传递参数 */
			intent.putExtra(NewsContentFragement.TAG_NEWS_ID, id);
			startActivity(intent);
		}

	}

}

(4) 新增了 NewsContentActivity

package cn.org.octopus;

import android.app.Activity;
import android.os.Bundle;

public class NewsContentActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		/* 设置布局文件 */
		setContentView(R.layout.activity_news_content);

		/* 创建 Fragement */
		NewsContentFragement fragement = new NewsContentFragement();
		/* 创建绑定的数据 */
		Bundle bundle = new Bundle();
		/* 从Activity 获取 启动该 Activity 的 Intent */
		int id = getIntent().getIntExtra(NewsContentFragement.TAG_NEWS_ID, 0);
		bundle.putInt(NewsContentFragement.TAG_NEWS_ID, id);
		/* 设置数据给 Fragment */
		fragement.setArguments(bundle);
		/* 开启事务 操作 Fragement 并提交 */
		getFragmentManager().beginTransaction().add(R.id.news_content, fragement).commit();
	}
}

(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 详解的更多相关文章

  1. 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING

    <Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th  2014 Email:skyseraph00@163.com 更多精彩请直接 ...

  2. 【Android基础】Fragment 详解之Fragment生命周期

    上一篇文章简单介绍了一下Fragment,这一篇文章会详细的说一下Fragment的生命周期和创建一个用户界面. Fragment的主要功能就是创建一个View,并且有一个生命周期来管理这个View的 ...

  3. 【Android基础】Fragment 详解之Fragment介绍

    Fragment在Android 3.0( API 11)引入,是为了支持在大屏上显示更加动态.灵活的UI,比如在平板和电视上.Fragment可以看作是嵌套的Activity,类似ActivityG ...

  4. 转:android Support 兼容包详解

    本文转自stormzhang的ANDROID SUPPORT兼容包详解 背景 来自于知乎上邀请回答的一个问题Android中AppCompat和Holo的一个问题?, 看来很多人还是对这些兼容包搞不清 ...

  5. 安卓开发之详解getChildFragmentManager和getsupportFragmentManager和getFragmentManager详解

    安卓开发之详解getChildFragmentManager和getsupportFragmentManager和getFragmentManager详解 getFragmentManager()所得 ...

  6. ANDROID L——Material Design详解(UI控件)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! Android L: Google已经确认Android L就是Android Lolli ...

  7. Cordova 打包 Android release app 过程详解

    Cordova 打包 Android release app 过程详解 时间 -- :: SegmentFault 原文 https://segmentfault.com/a/119000000517 ...

  8. Cocos2d-x 3.X手游开发实例详解

    Cocos2d-x 3.X手游开发实例详解(最新最简Cocos2d-x手机游戏开发学习方法,以热门游戏2048.卡牌为例,完整再现手游的开发过程,实例丰富,代码完备,Cocos2d-x作者之一林顺和泰 ...

  9. Fragment详解之三——管理Fragment(1)

    相关文章: 1.<Fragment详解之一--概述>2.<Fragment详解之二--基本使用方法>3.<Fragment详解之三--管理Fragment(1)>4 ...

  10. Android中Service(服务)详解

    http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...

随机推荐

  1. Goland 提示 :configuration is still incorrect 的解决

    安装好 Goland 后,调试编译的时候提示 goland configuration is still incorrect,百度 和 Google 都没有明确答案 Google 上有一些提示,但是也 ...

  2. JS的replace默认只替换第一个匹配项

    1. JS的replace默认只替换第一个匹配项. 解决方法: 使用正则表达式进行匹配替换[   ①.replace(new RegExp(②,"g") ,③);   ] ①:包含 ...

  3. Python练习之pillow

    此系列意在记录于一些有趣的程序及对其的总结. 问题来源: https://github.com/Yixiaohan/show-me-the-code https://github.com/HT524/ ...

  4. Node.js TTY

    稳定性: 2 - 不稳定 tty 模块包含 tty.ReadStream 和 tty.WriteStream 类.多数情况下,你不必直接使用这个模块. 当 node 检测到自己正运行于 TTY 上下文 ...

  5. Latex:入门教程

    http://blog.csdn.net/pipisorry/article/details/54571521 总的来说,LaTex是一套排版系统,与word那种所见即所得对排版方式不太,用LaTex ...

  6. 自定义Java注解的方式与应用

    注解的作用 Annotation(注解)是JDK 5.0引入的特性,它的基本作用就是修饰编程元素. 注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记.编译器.开发工具或其他程序可以用反射 ...

  7. J2EE进阶(十六)Hibernate 中getHibernateTemplate()方法使用

    J2EE进阶(十六)Hibernate 中getHibernateTemplate()方法使用   spring 中获得由spring所配置的hibernate的操作对象,然后利用此对象进行,保存,修 ...

  8. pycallgraph 追踪Python函数内部调用

    安装 安装pycallgraph 安装依赖 使用 待测脚本 追踪脚本 追踪结果 高级篇 隐藏私密函数 控制最大追踪深度 总结 GitHub上好代码真的是太多了,名副其实的一个宝藏.但是最近自己也反思了 ...

  9. android面试手册

    1. Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念 DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚 ...

  10. Android逆向工程

    在Root前提下,我们可以使用Hooker方式绑定so库,通过逆向方式篡改数值,从而达到所谓破解目的.然而,目前无论是软件加固方式,或是数据处理能力后台化,还是客户端数据真实性验证,都有了一定积累和发 ...