《一个Android工程的从零开始》-6、base(五) BaseFragment封装
来源:互联网 发布:淘宝海运到美国 编辑:程序博客网 时间:2024/06/04 18:07
先扯两句
首先呢,要先跟大家道个歉,之前结束BaseActivity部分和写ButterK的部分都有些兴奋,博客发出去以后,竟然忘了将代码提交git了,一打开项目,看都是绿色、蓝色的文件,实在是不好意思,已经提交了,有需要的可以去查看了。 我的代码都是随着写博客随着完善的,所以希望今天的最后能够想起来提交,不然。。。大家不要打我,我怕疼。。。
MyBaseApplication (https://github.com/BanShouWeng/MyBaseApplication)
正文
Fragment基本方法
前面也提到了,上一篇已经将BaseActivity封装结束了,当然只是一些基本的操作,在后续的过程中,肯定会随着新功能的运用逐步去完善。 而今天我们所研究的内容呢,看到标题大家自然也就明白了,就是BaseFragment的封装,当然,与前一段所说一样,这个部分的内容也是暂时性的一些基础内容,并不是说今天的内容搞定了,以后都不需要进到BaseFragment中做任何修改了的,所以因人而异,因项目而异。 之前都是先分析,再贴代码,今天改改套路,先开个大:
package com.banshouweng.mybaseapplication.base;import android.content.Context;import android.net.Uri;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.banshouweng.mybaseapplication.R;/** * 《一个Android工程的从零开始》 *@author 半寿翁 *@博客: *@ CSDN http://blog.csdn.net/u010513377/article/details/74455960 *@ 简书 http://www.jianshu.com/p/1410051701fe */public class BaseFragment extends Fragment { private OnFragmentInteractionListener mListener; private Unbinder unbinder; public BaseFragment() { // Required empty public constructor } /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @return A new instance of fragment BaseFragment. */ // TODO: Rename and change types and number of parameters public static BaseFragment newInstance() { BaseFragment fragment = new BaseFragment(); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, unbinder = ButterKnife.bind(this, view); // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_base, container, false); } // TODO: Rename method, update argument and hook method into UI event public void onButtonPressed(Uri uri) { if (mListener != null) { mListener.onFragmentInteraction(uri); } } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; } @Override public void onDestroyView() { super.onDestroyView(); unbinder.unbind(); } /** * This interface must be implemented by activities that contain this * fragment to allow an interaction in this fragment to be communicated * to the activity and potentially other fragments contained in that * activity. * <p> * See the Android Training lesson <a href= * "http://developer.android.com/training/basics/fragments/communicating.html" * >Communicating with Other Fragments</a> for more information. */ public interface OnFragmentInteractionListener { // TODO: Update argument type and name void onFragmentInteraction(Uri uri); }}
细心的或许会发现,我把包名给改了,填上banshouweng,实在是所以找的demo之类的都有这类的,没办法,网上找的demo都有类似的个人推广,我怎么忍心不给自己也添加一个呢,嘿嘿。
好了,进入正题。
上面呢,是创建一个block fragment后,AS自动给生成的一系列方法,当然,如果你也创建一个,应该会比我这个内容更多,因为上面贴出来的已经是经过我筛选过的了,毕竟你让一个喜欢偷懒的人,上来就看那么多的代码,反正我个人是忍不了。
下面就说一下我留下的这些代码都有上面用:
- BaseFragment
构造方法,这里面暂时唯一一个没有用到的方法,留下它的目的只是单纯的为了与下面的newInstance做对比,当然,如果不适用onCreate中的getArgument传递参数的时候,可以用构造方法传参,只不过现在都很少使用了罢了。 - newInstance
这里的作用与上面的构造方法相同,毕竟可以看到,其中就只有一个构造方法罢了,至于为什么当下很流行使用newInstance而不使用构造方法,主要还是为了去耦合。好吧,我也比较讨厌这些看起来特别高大上的专业词汇。就我个人理解,使用它最好的一种玩法就是复用,如果使用构造方法的时候,就只能创建一个对象,而如果将newInstance中创建的对象放在变成全局变量,再做个判空处理,你就会发现,这里我们可以在多场合使用同一个对象,都不用传参数了,甚至连状态都保留了。(以上说明的是对newInstance与构造方法的区别,并不仅限于Fragment) - onCreate
用于获取argument,也就是从Activity中传递来的参数获取,暂时没有发现其他用处。 - onCreateView与onViewCreated(上面代码中没有)以及onDestroyView
onCreateView是当视图创建前执行,onViewCreated是在视图创建完毕后执行,是一对,一般是用来解析布局的,当然如果看了我上一篇博客,应该会看到其中写的一段,关于ButterKnife.findById在Fragment中运用的,其中的view参数就可以使用这里解析的布局代替,而这个方法的使用就是在onViewCreated中,同时在onViewCreated方法运行之后,才可以对我们的控件做操作,不然很容易出现空指针异常。而onCreateView与onDestroyView这一对的使用则是ButterKnife的绑定与解绑,方法参见前面的代码就可以。 - onAttach
Fragment与Activity绑定时执行的方法,有的时候在Fragment中使用getActivity会报空指针异常,所以这个时候我们就需要onAttach来帮忙了,因为你会看到,它的参数正是Context,只要将它保存起来,在使用的时候直接调用就可以解决这个问题了。不过也正因为这个操作我们在BaseFragment封装时做了操作,所以一般直接使用Context,也就不需要再去调用它了。 - onDetach
与上面的onAttach方法可以算做一对,上面是绑定Activity的方法,onDetach则是解绑时执行的方法,而这个方法中做的操作,就是将我们整个Fragment中使用到的与Activity相关联的参数置空,防止发生OOM。 - OnFragmentInteractionListener与onButtonPressed
这个部分是之前还打算自己写的内容,没想到现在AS已经为我们提出了解决方法。作用就是将Fragment中的参数传递到Activity中,AS生成的这个传递的是Uri,我们在使用的时候,可以自行定义所要传递的内容,同样也可以在接口中写添加其他的抽象方法,而不需要的时候也可以不写。onButtonPressed的目的是告诉我们这个部分的代码应该如何使用,根据自己的需求灵活运用即可。
BaseFragment封装
其实这个部分呢,说起来复杂,可也比较简单,毕竟之前我们已经封装过了BaseActivity,很多的方法都是共通的,所以对应的部分,我们只需要粘贴过来,略作修改即可,所以这里,我就将我们一些有差异的地方写出来,其他的部分,大家看一下代码就好。
方法封装
写BaseActivity的时候,我们是先从布局开始的,为了公平起见,写BaseFragment就从方法封装开始好了。
当然,如果你真的认为我这么安排是什么所谓的公平,那就只能说明你太单纯了,作为我们这么一个懒人,哪有什么时间去考虑什么公平,有那时间睡觉多好。所以这么安排只有一个原因,那就是方法的封装更简单。
不过在方法封装之前,我们有一件事需要处理一下,也就是刚刚onAttach中所说的内容。而且对于这部分,看过我前面博客的应该会了解到,在写BaseActivity方法封装的时候,说到了为什么会专门创建两个对象,Context和Activity,就是为了与Fragment中引用的向统一,至于这两个对象是否还有其他作用就有待我们将来探索了,但是在Fragment中可以肯定是很必要的。
既然必要那就创建之,上代码:
/** * 用于传递的上下文信息 */ public Context context; public Activity activity; @Override public void onAttach(Context context) { super.onAttach(context); this.context = context.getApplicationContext(); activity = (Activity) context; }
以上就完成了获取Context和Activity的操作,后面Fragment的运用中很大程度上依赖这两个对象,这部分个人的建议就是,直接将BaseActivity中的方法复制过来,然后就会看到个别报错的地方,然后在调用的方法前面添加上“activity. ”,this判断是否与所绑定的Activity有关,有的替换成activity,没有的替换成context,就完成了方法的封装,例如:
//报错部分 public void startActivity(Class<?> clz) { startActivity(new Intent(this, clz)); } //修改之后 public void startActivity(Class<?> clz) { startActivity(new Intent(context, clz)); } //修改前 case R.id.base_back: if (isResetBack) { onClickBack.clickBack(); } else { finish(); } break; //修改后 case R.id.base_back: if (isResetBack) { onClickBack.clickBack(); } else { activity.finish(); } break;
这么多代码直接针贴过来就可以,包括网络监听以及进度条的部分,当然,如果实在偷懒,进度条的部分可以不用复制过来,而是在需要使用的Fragment中,使用上面说到的接口OnFragmentInteractionListener直接调用BaseActivity中的进度条。
最后需要说明的一点,个人建议,将BaseActivity在onCreate中执行的方法调用都放置在onViewCreated方法中进行,放置出现没有必要的空指针。
Title
看到标题大家应该知道,前面我们已经将方法封装完成了,对于这种可以偷懒的任务我可是相当喜欢了。
可是很不幸的是,这次需要花些心思的竟然落在Title上,不过好在难度有限,让我这样的懒人很感动啊。
Title的封装
哎,看到Title,我就又想起来第一篇博客里面的那三种情况了,说起来还真是麻烦,还需要考虑那么多因素,重新写一个真心一万个不愿意,或者有人会想到,我们可以直接把BaseActivity布局中的直接复制,贴到BaseFragment的布局,想想也是个方法,可是万一下次再什么地方还需要这个Title布局(虽然我暂时还没想到哪里还会需要),我们还需要去找布局,再复制,对于我这种懒人来说,怎么可能忍得了!
所以就有了上面的标题,那就是Title的封装,你没有看错,布局也是可以封装的,而且也不困难,下面我们就开始。
首先是需要创建一个xml布局,类型当然选择的是Layout,我这里将这个布局很无脑的命名为title_layout,随后将BaseActivity中的Title布局剪切下来粘贴到这个布局中,也就成了这个样子:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="@dimen/title_height" android:background="@color/colorPrimary"> <ImageView android:id="@+id/base_back" android:layout_width="50dp" android:layout_height="50dp" android:padding="@dimen/size_13" android:src="@mipmap/back" android:tint="@android:color/white" /> <TextView android:id="@+id/base_title" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_centerInParent="true" android:gravity="center" android:text="@string/title" android:textColor="@android:color/white" android:textSize="@dimen/size_20" /> <ImageView android:id="@+id/base_right_icon2" android:layout_width="50dp" android:layout_height="50dp" android:layout_toLeftOf="@+id/base_right_icon1" android:contentDescription="@string/second_function_key" android:padding="@dimen/size_13" android:src="@mipmap/add" android:tint="@android:color/white" android:visibility="gone" /> <ImageView android:id="@+id/base_right_icon1" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentRight="true" android:contentDescription="@string/first_function_key" android:padding="@dimen/size_13" android:src="@mipmap/more" android:tint="@android:color/white" android:visibility="gone" /> <TextView android:id="@+id/base_right_text" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentRight="true" android:gravity="center" android:text="@string/make_sure" android:textColor="@android:color/white" android:textSize="@dimen/size_17" android:visibility="gone" /></RelativeLayout>
可是很显然,剪切下来,那么在BaseActivity中也没有了这个Title布局,这可怎么办呢,下面就让我们见证一下Title疯转的神奇之处吧,在BaseActivity布局之前Title的位置上,写如下的代码:
<include android:id="@+id/base_title_layout" layout="@layout/title_layout"></include>
是不是看到之前被我们剪切的Title布局又重新显示出来了?至于include是什么,怎么用,我这种小菜鸟就不在此多言了,还是直接上链接,大家一起去瞻仰一下大神们是如何讲解的,没错就是我们郭霖郭神的Android最佳性能实践(四)——布局优化技巧。当然,打击可以看到优化的部分除了include还有merge以及ViewStub,大家可以看一下郭神的博客自行理解一下,我这里后面的博客应该也会用到这两部分的优化,不过我这种懒人你们懂的,没用到的时候,怎么可能写到自己的博客里,所以这部分只能在后面随缘讲解了。
好了闲言少叙,搞定了BaseActivity,下面我们也该处理一下BaseFragment中的布局了,不过很好运的是由于Fragment也是在Activity的布局中使用的,所以既然我们的BaseActivity外已经 嵌套了一层ScrollView了,所以BaseFragment的布局中就不再需要多此一举了,我们只需要进行其中的布局即可,代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/base_scroll_view" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.banshouweng.mybaseapplication.base.BaseFragment"> <include android:id="@+id/base_title_layout" layout="@layout/title_layout"></include> <LinearLayout android:id="@+id/base_main_layout" android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1" android:orientation="vertical"></LinearLayout></LinearLayout>
是不是看起来要简洁一些,至此我们的Title的封装也就结束了,当然,也就是include的使用罢了。
Title对应的方法
1、初始化控件
这里需要注意的地方是,偷懒的我把initView改成了使用ButterKnife的样子,所以在BaseActivity中的是如下代码:
/** * 控件初始化 */ public void initView() { baseBack = ButterKnife.findById(activity, R.id.base_back); baseRightIcon1 = ButterKnife.findById(activity, R.id.base_right_icon1); baseRightIcon2 = ButterKnife.findById(activity, R.id.base_right_icon2); baseTitle = ButterKnife.findById(activity, R.id.base_title); baseRightText = ButterKnife.findById(activity, R.id.base_right_text); baseTitleLayout = ButterKnife.findById(activity, R.id.base_title_layout); baseMainLayout = ButterKnife.findById(activity, R.id.base_main_layout); baseScrollView = ButterKnife.findById(activity, R.id.base_scroll_view); }
而在BaseFragment切记一定要修改成如下:
/** * 控件初始化 */ private void initView() { baseBack = ButterKnife.findById(currentLayout, R.id.base_back); baseRightIcon1 = ButterKnife.findById(currentLayout, R.id.base_right_icon1); baseRightIcon2 = ButterKnife.findById(currentLayout, R.id.base_right_icon2); baseTitle = ButterKnife.findById(currentLayout, R.id.base_title); baseRightText = ButterKnife.findById(currentLayout, R.id.base_right_text); baseTitleLayout = ButterKnife.findById(currentLayout, R.id.base_title_layout); baseMainLayout = ButterKnife.findById(currentLayout, R.id.base_main_layout); baseScrollView = ButterKnife.findById(currentLayout, R.id.base_scroll_view); }
其中的currentLayout是在onCreateView中保存下来的,这么做的主要原因是,如果这里我们使用的是activity,则表示这些代码我们是让ButterKnife去Fragment所绑定的Activity中去寻找控件,而我们的目的却是让其在当前的Fragment中寻找,所以这里不能使用activity,而需要替换成currentLayout。
2、Title方法封装
所有的控件都已经初始化完成,那么我们也该进行方法的封装了,其实说来说去还是那几个方法而已,我们还是只需要复制过来即可,而其调用的方式也与BaseActivity中封装的方法调用的方式完全相同,所以这部分到此也就结束了。
ps:为了防止结束的太过仓促,在结尾的部分,我还是对BaseActivity做一些补充比较好,那就是在BaseActivity中,我们使用了ScrollView,是为了兼容一些分辨率过低的手机,防止页面内容显示不全,可是有一些页面是没有Title的,例如首页就经常不需要使用Title,而之前我想的是,直接使用setContentView方法,所以就没有做对应的处理,却忽略了如果一旦使用了setContentView方法,那么ScrollView的效果就不在了,所以就又添加了一个隐藏头布局的方法:
/** * 隐藏头布局 */ public void hideTitle() { baseTitleLayout.setVisibility(View.GONE); }
当然,没有确定Fragment中是否需要使用,我们可以先封装到BaseFragment中,也可以等用到时再去封装。
附录
《一个Android工程的从零开始》目录
- 《一个Android工程的从零开始》-6、base(五) BaseFragment封装
- 《一个Android工程的从零开始》-7、base(六) BaseFragment的运用
- 《一个Android工程的从零开始》-8、base(七) Retrofit的封装
- 《一个Android工程的从零开始》-5、base(四) BaseActivity——方法封装
- 《一个Android工程的从零开始》-2、base(一) BaseActivity布局
- 《一个Android工程的从零开始》-4、base(三) BaseActivity——Title
- 《一个Android工程的从零开始》9、base(八) 数据存储-SharedPreferences
- 《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用
- 《一个Android工程的从零开始》阶段总结与修改1-base
- android BaseActivity与BaseFragment的封装
- 对BaseFragment的封装
- 《一个Android工程的从零开始》- 目录
- Android 6.0 运行时权限 fragment的简单封装 basefragment
- BaseActivity与BaseFragment的封装
- 4、Basefragment的封装使用
- BaseActivity与BaseFragment的封装
- BaseActivity和BaseFragment 的封装
- Android 基类Base的封装
- 发布高质量外链的实用方法
- R-CNN、Fast R-CNN、Faster R-CNN、Mask R-CNN总结
- jquery
- PLC控制系统设计的基本内容
- 【Java深入】String.intern()详解
- 《一个Android工程的从零开始》-6、base(五) BaseFragment封装
- How to fix 'Inconsistency detected by ld.so: dl-version.c: 224: _dl_check_map_versions'
- final,finally和finalize的区别
- 第三个案例(移动设备)
- 2017-7-14(注册登录篇)
- 接口-自动化测试(API+WCF)
- 算法--中兴面试:输入两个整数 n 和 m,从数列1,2,3.......n 中随意取几个数, 使其和等于 m
- Arrays.asList(T...a)的使用问题
- MTK的充电方案—PMIC充电