zoukankan      html  css  js  c++  java
  • 【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 */
    	@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 自带的布局, 在 sdkplatformsandroid-10data
    eslayout 文件夹下
    		 *  */
    		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


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    总结!!!总结!!!
    Beta 总结
    BETA-7
    BETA-6
    BETA-5
    BETA-4
    BETA-3
    华为云-软件产品案例分析
    BETA-2
    BETA-1
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4842319.html
Copyright © 2011-2022 走看看