| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Android Fragment -> 正文阅读 |
|
[移动开发]Android Fragment |
1.Fragment fragment译为“碎片”,是Android 3.0(API 11)提出的,最开始是为了适配大屏的平板。 Fragment看起来和Activity一样,是一个用户界面。可以结合多个Fragments到一个activity中来构建一个有多方面功能的UI,还可以重用同一个Fragment在多个activities中。Fragment可以当成是activity的一个组件,每个Fragment有单独的生命周期,可以在activity运行时进行添加和移除Fragment。因此,相比较于activity,Fragment更加轻量级,更加灵活。 一个Fragment总是被植入在一个activity中 ,并且其生命周期受其父activity直接影响,比如activity处于暂停,则其中的Fragment都暂停;activity销毁,则所有Fragment都销毁。但是,当一个activity运行时,你可以独立的操作每一个Fragment,比如添加和删除他们。进行类似的操作时,可以将Fragment添加入被activity管理的后退栈中,这样用户可以通过点击返回按钮来返回之前打开的Fragment。 Fragment可以作为activity的一部分添加到布局文件中,通过声明元素作为ViewGroup的一部分。也可以将Fragment作为一个没有自己UI的不可见的activity的工人。 总结一下: ①Fragment是依赖于Activity的,不能独立存在。 ②一个Activity里可以有多个Fragment。 ③一个Fragment可以被多个Activity重用。 ③Fragment有自己的生命周期,并能接收输入事件。 ④可以在Activity运行时动态地添加或删除Fragment。 ? 2.Fragment生命周期 ?常见的周期流程 ①Activity加载Fragment的时候,依次调用:onAttach() -> onCreate() -> onCreateView() -> onActivityCreated() -> onStart() ->onResume() ②当做出一个悬浮的对话框风格的Activity,或者其他,就是让Fragment所在的Activity可见,但不获得焦点:onPause() ③当对话框关闭,Activity又获得了焦点:?onResume() ④当替换Fragment,并调用addToBackStack()将它添加到Back栈中:onPause() -> onStop() -> onDestoryView() 。注意,此时的Fragment还没有被销毁哦。 ⑤当按下键盘的回退键,Fragment会再次显示出来:onCreateView() -> onActivityCreated() -> onStart() -> onResume() ⑥如果替换后,在事务commit之前没有调用addToBackStack()方法将Fragment添加到back栈中,或者退出了Activity的话,那么Fragment将会被完全结束,Fragment会进入销毁状态: onPause() -> onStop() -> onDestoryView() -> onDestory() -> onDetach() ? 3.Fragment创建 ①静态加载--以<fragment>标签的形式添加到Activity的布局当中。 ?1)定义Fragment的布局,就是fragment显示内容 2)自定义一个Fragment类,需要继承Fragment或者它的子类,重写onCreateView()方法,在该方法中调用inflater.inflate()方法加载Fragment的布局文件,接着返回加载的view对象。 public class Fragmentone extends Fragment { ? ? private View view; ? ? @Override ? ? public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ? ? ? ? if(view == null) { ? ? ? ? ? ? View view = inflater.inflate( R.layout.fragment1, container,false); ? ? ? ? } ? ? ? ? return view; ? ? } } 3)在需要加载Fragment的Activity对应的布局文件中添加fragment的标签,注意name属性是全限定类名,就是要包含Fragment的包名。 4)Activity在onCreate( )方法中调用setContentView()加载布局文件。 ②动态加载--通过java代码将fragment添加到已存在的宿主Activity中 动态添加fragment常用的类: FragmentManager:用来管理Activity中的fragment,app包中使用getFragmentManager() v4包中getSupportFragmentManager。可以通过findFragmentById获取指定的Fragment,可以调用popBackStack()方法弹出后台Fragment,还可以调用addToBackStack()方法加入栈,或监听后台栈的变化:addOnBackStackChangeListener。 FragmentTransaction:事务,用来添加、移除、替换fragment,记得在操作完后用commoi()提交事务。FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务 transaction.add():往Activity中添加一个Fragment transaction.remove() :从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。 transaction.replace():使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体。 transaction.hide():隐藏当前的Fragment,仅仅是设为不可见,并不会销毁 transaction.show():显示之前隐藏的Fragment transaction.commit():提交一个事务 detach():会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。 注意:在用fragment的时候,可能会经常遇到Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。 这些基本是操作Fragment的所有方式了,在一个事务开启到提交可以进行多个添加、移除、替换等操作。 注意:使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。 attach():重建view视图,附加到UI上并显示。 1)比如:在FragmentA中的EditText填了一些数据,当切换到FragmentB时,如果希望回到A还能看到数据,则使用的就是hide和show;也就是说,希望保留用户操作的面板,可以使用hide和show,当然了不要使劲在那new实例,进行下非null判断。 2)再比如:不希望保留用户操作,可以使用remove(),然后add();或者使用replace()这个和remove、add是相同的效果。 3)remove和detach有一点细微的区别:在不考虑回退栈的情况下,remove会销毁整个Fragment实例,而detach则只是销毁其视图结构,实例并不会被销毁。那么二者怎么取舍使用呢?如果当前Activity一直存在,在不希望保留用户操作的时候,可以优先使用detach。 ? 4.Fragment与Activity的交互 1)组件获取 Fragment获得Activity中的组件: getActivity().findViewById(R.id.list); Activity获得Fragment中的组件(根据id和tag都可以):getFragmentManager.findFragmentByid(R.id.fragment1); 2)数据传递 ①Activity传递数据给Fragment 采用Bundle方式:在activity中创建Bundle数据包,把要传的值存入bundle,调用Fragment实例的setArguments(bundle)从而将Bundle数据包传给Fragment,,然后Fragment中调用getArguments获得Bundle对象,然后进行解析就可以了。 举个例子:动态添加fragment的时候,在添加每个fragment之前,使用Bundle传输数据给每个fragment。 mManager = getSupportFragmentManager(); mTransaction = mManager.beginTransaction(); homeFragment = new HomeFragment(); //创建Bundle对象,并存储数据 Bundle bundle=new Bundle(); bundle.putString("home","Home"); homeFragment.setArguments(bundle); fragment中接收数据: Bundle bundle = this.getArguments(); String home = bundle.getString("home"); ②Fragment传递数据给Activity 采用接口回调方式:在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口,Fragment就可以通过回调接口传数据了。 首先定义一个接口回调接口:(Fragment中) public interface ICallBack{?? ? ? public void getResult(String result);?? }?? 接着在Fragment中设置接口回调的方法: public void getData(ICallBack callBack){?? ? ? String msg = editText.getText().toString();?? ? ? callBack.getResult(msg);?? }?? 最后在Activity中回调: leftFragment.getData(new ICallBack() {?? ?@Override?? ? ?public void getResult(String result) {? ? ? ? ? Toast.makeText(this, result, 1).show();?? ??? } });? ③Fragment与Fragment之间的数据互传 不同的fragment之间的通信要依靠ativity来完成。可以看成Fragment->Activity->Fragment,因为两个或多个fragment是依附于同一个activity,所以完全可以通过把值传递到共同依附的Activity,然后通过Bundle传给另一个fragment。 方式一:先调用findFragmentById()方法根据id获得fragment的对象,然后调用fragment中的方法进行赋值。 manager.findFragmentById(); //根据ID来找到对应的Fragment实例,主要用在静态添加fragment的布局中,因为静态添加的fragment才会有ID manager.findFragmentByTag();//根据TAG找到对应的Fragment实例,主要用于在动态添加的fragment中,根据TAG来找到fragment实例 manager.getFragments();//获取所有被ADD进Activity中的Fragment 然后,直接在一个Fragment中调用另外一个Fragment的公开方法,前提是要先拿到另外一个Fragment的实例。 一般情况下,都是动态添加Fragment的,所以通过在add每个Fragment的时候,给每个Fragment设置个tag。 manager = this.getSupportFragmentManager(); transaction = manager.beginTransaction(); LeftFragment leftFragment = new LeftFragment(); RightFragment rightFragment = new RightFragment(); transaction.add(R.id.left, leftFragment, "left"); transaction.add(R.id.right, rightFragment, "right"); transaction.commit(); 在Activity创建的时候,添加上所有的fragment,并为每个fragment设置tag,这样才会在每个fragment中通过findFragmentByTag()时,不会出现空指针。 在LeftFragment中: RightFragment rightFragment = (RightFragment) getActivity().getSupportFragmentManager().findFragmentByTag("right"); if (rightFragment == null) return; rightFragment .setTextView("right now"); 这样就实现了在LeftFragment里给RightFragment传值的效果。 这种方式是两个fragment直接通信的。(不推荐使用) 方式二:通过接口回调的方法实现两个fragment之间的通信 比如点击MessageFragment的Button按钮,给CommunityFragment中的TextView传递数据。就需要在MessageFragment中定义接口,并定义回调的方法,该方法的参数中传一个String的字符串。接着让附属Activity实现这个接口,并重写回调方法,也就得到到传过来的数据,然后通过findFragmentByTag()的方法获取要传给的CommunityFragment的实例。 在CommunityFragment中定义一个方法用来接收这个数据,然后用对象直接调用这个方法将参数传递给这个方法,就可以了。 方式三:其他方式 EventBus:使用方便,但其使用的是反射原理,会有稍微的延迟,并且他人维护不方便; static静态变量:使用方便,但是,每个static变量都会占用一块内存区,Android系统分配给每个App的内存是有限的(63M),过多很容易造成App内存溢出; 广播Broadcast Receiver:Android的广播是有限制的,除了系统的广播外,其他的广播尽量少用。另外,广播会有延迟; 接口:接口是常用的Fragment之间的通讯方式,通过一个主Activity作为通讯桥梁(谷歌官方声明:两个Fragment之间永远不要直接通讯),实现两个Fragment之间的通讯。 接口的方式是推荐的,但是,传统的接口方式会造成一些问题,如果主Activity实现了多个Fragment的通讯回调接口,那就需要implements很多接口,类中还要实现一大堆接口的方法,显得有点繁琐。 |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 0:06:15- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |