Fragment翻译过来叫碎片,但是我个人觉得可以理解为具有生命周期的View
由于Fragment是3.0以后的东西,对于适应低版本,那我们只能使用谷歌官方提供的android-support-v4.jar这个包了,最快捷的办法就是右击工程名,选择Android Tools——add support library...,即可添加这个包了
由于3.0以下的Activity里面没有对Fragment的支持,所以选择继承android-support-v4.jar包中的FragmentActivity,其功能跟3.0及以后的版本的Activity的功能一样
DEMO下载:
FragmentTest.zip
底部导航加顶部导航,使用FragmentTabHost,Fragmetn,FragmentActivity组成,代码已经打包上传了
1、首先,底部导航的实现,FragmentTabHost和以前的TabHost的区别就是增加了对Fragment的支持,这里的实现和其他使用TabActivity是一样的,只是选项卡的切换已经从activity变成fragment了
2、这里主要讲一下顶部导航的实现,为了让大家对fragment更好的理解,这里我没有采用FragmentTabHost,而是放了三个Button
这里有个FragmentTransaction(事务),这个是Fragment切换的核心类,它有两个方法:replace,add,一个是替换Fragment,一个是添加Fragment,两者的区别是:replace=remove掉旧fragment,add新的fragment
FragmentManager(碎片管理器),用来管理当前Activity中所有的Fragment
每次替换或者添加后,都要commit一样,才能算一个完整的事务,这里用了Fragment嵌套,还要注意一个问题,由于我当时没注意,导致想了好久才找出问题的原因所在,如果你是嵌套了Fragment,那么使用FragmentManager的一定要注意你当前的Fragment是属于嵌套的fragment还是顶层的Fragment,如果是顶层Fragment,那么你调用FragmentManager的时候,应该这样写getActivity().getSupportFragmentManager(),如果是嵌套的fragment那么应该这样写getChildFragmentManager()
Fragment基础:http://www.cnblogs.com/TerryBlog/archive/2012/02/17/2355753.html
(1) Looper类别用来为一个线程开启一个消息循环。默认情况下Android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环)
Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。
(2) 通常是通过Handler对象来与Looper交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。
默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,在主线程中定义,其是与主线程的Looper绑定。
mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).
Looper.myLooper():Return the Looper object associated with the current thread 获取当前进程的looper对象。
还有一个类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。
(3) 在非主线程中直接new Handler() 会报如下的错误:
E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception
E/AndroidRuntime( 6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。
(4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。
注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
(5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。
Toast或者Dialog中都有一个Handler的成员变量,在初始化时都会跟着初始化,而Toast或者Dialog中的Handler都需要一个Looper,所以需要在包含该Toast或者Dialog的线程中(如下面的Timer线程)初始化Looper。Looper.prepare();
问题代码:
private Handler myHandler = new Handler() { public void handleMessage(Message msg) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { InputMethodManager m = (InputMethodManager) editText .getContext().getSystemService( Context.INPUT_METHOD_SERVICE); m.showSoftInput(editText, 0); // Looper.prepare(); Toast.makeText(Main.this, "show", Toast.LENGTH_LONG).show(); Looper.loop(); } }, 1000); } }
Toast 和 Looper,一个属于 android.widget,一个属于 android.os,两个貌似联系不怎么紧密的类,却通过下面这个异常联系到了一起:
E/AndroidRuntime( 1819): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() E/AndroidRuntime( 1819): at android.os.Handler.<init>(Handler.java:121) E/AndroidRuntime( 1819): at android.widget.Toast.<init>(Toast.java:68) E/AndroidRuntime( 1819): at android.widget.Toast.makeText(Toast.java:231)
Handler.java:121
119 mLooper = Looper.myLooper(); 120 if (mLooper == null) { 121 throw new RuntimeException( 122 "Can't create handler inside thread that has not called Looper.prepare()");}
Toast.java:68 ——>成员变量,在初始化时会跟着初始化
68 final Handler mHandler = new Handler();
由以上的错误信息可以看出:程序要创建 handler,但是发现Looper.prepare还没有被调用。通过 Android SDK 中的Reference可以看到,Looper、Handler 的调用是非常有讲究的,如下面示例代码:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
言归正题,继续寻找 Toast、Looper 和 Handler 三者之间的联系,也许谜底就能解开了。欲揭谜底,从源码入手是一条捷径。
Toast.java 的第231行的代码是创建一个新的Toast实例,而实例化的过程中,就需要执行第68行,也就是声明并创建Handler(成员变量)的实例。那么来看Handler.java的第121行到底做了什么,如下所示:
119 mLooper = Looper.myLooper(); 120 if (mLooper == null) { 121 throw new RuntimeException( 122 "Can't create handler inside thread that has not called Looper.prepare()");}
到此,距离真相的解开近了一大步,既然抛出了 RuntimeException,那么 mLooper 肯定是 null,但是为什么 Looper.myLooper() 会返回 null?继续进入到 Looper.java 中寻根究底。
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static final Looper myLooper() { return (Looper)sThreadLocal.get(); }
以上就是 myLooper() 方法的真实面貌,通过注释可以看出问题的真正原因在于当前线程并没有绑定 Looper,返回为 null 是正确但非正常的结果。
1.开始启动一个最小系统minifs_sd
2.然后启动busybox文件系统
lrwxrwxrwx 1 root root 11 7月 5 2011 linuxrc -> bin/busybox
3.执行etc/init.d/rcS文件
#!/bin/sh rm -f /var/run/dbus/* rm -rf /tmp/.* rm -rf /tmp/* #/bin/sh /etc/init.d/modules mount -a /sbin/mdev -s #hwclock -sl #mkfs.ext3 /dev/ram0 #mount /dev/ram0 /tmp #mount -t sysfs none /sys /sbin/syslogd #/usr/sbin/telnetd #** install system **# /bin/sh /minifs_sh/install_cx_ctrl.sh&
4.执行rcS文件内的install_cx_ctrl.sh
#!/bin/sh ############################################################## #Todo on led for start /bin/mount /dev/mmcblk0p1 /mnt/sd echo "******** write backup kerner ********" /usr/sbin/flash_eraseall /dev/mtd1 /usr/sbin/nandwrite -p /dev/mtd1 /mnt/sd/zImage* echo "******** write use kerner ********" /usr/sbin/flash_eraseall /dev/mtd2 /usr/sbin/nandwrite -p /dev/mtd2 /mnt/sd/zImage* echo "******** write minifs ********" /usr/sbin/ubiformat /dev/mtd3 -f /mnt/sd/minifs_ubi* echo "******** write userdata ********" /usr/sbin/ubiformat /dev/mtd4 -f /mnt/sd/user_data_ubi* echo "******** write rootfs ********" /usr/sbin/ubiformat /dev/mtd5 -f /mnt/sd/rootfs_ubi* sync #Todo off led for end echo "*** OK ***" poweroff ##############################################################
5.然后挂接文件执行安装程序