//省略…
//加上下面的脚本代码,然后sync你的项目
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
onBackPressed
在哪?我知道第一次使用Fragment
的人肯定都超想问这个问题.众所周知Fragment
本身是没有onBackPressed
的.不是Google
不设计,而是真的没法管理啊!!!,如果一个界面上有三四个地方都有Fragment
存在,一按回退键,谁知道要交给哪个Fragment
处理呢?所以Fragment
是"没有"onBackPressed
的.
在这里我的“没有”打了引号,因为实际上给Fragment
添加类似onBackPressed
的功能的办法是存在的,只是Google
把它设计成交给开发者自行管理了.
要想使用Fragment
的onBackPressed
,你可能需要先升级到AndroidX
.
这里可能有人会问AndroidX
是什么?
简单来讲AndroidX
就是一个与平台解绑的appcompat
(低版本兼容高版本功能)库,也就是说在build.gradle
中不需要再与compileSdkVersion
写成一样,例如之前这样的写法:
compile ‘com.android.support:appcompat-v7:24.+’
(注:使用24.+则表明使用 24. 开头的版本的最新版本,若直接使用+号则表明直接使用该库的最新版本。
现在可以写成:
implementation ‘androidx.appcompat:appcompat:1.1.0-alpha02’
(注:新的依赖方式implementation
与compile
功能相同,但是implementation
无法在该模块内引用依赖的依赖,但compile
可以,这么做的好处是可以加快编译速度。新的依赖方式api
与compile
完全相同,只是换了名字而已)
在Android Studo
中的Refactor->Migrate to AndroidX
的选点击之后即可将项目迁移到AndroidX
,在确认的时会提示你将项目备份以免迁移失败时丢失原有项目,通常情况下不会迁移失败,只是迁移的过程会花费很多的时间,如果项目很大,迁移时间会很长,这时即使Android Studio
的CPU
利用率为0
也不要关闭, 但是如果发生迁移失败,这时候就需要手动迁移了。
一些使用gradle
依赖的一些第三方库中的某些类可能继承了android.support.v4
包下的Fragment
,但迁移到AndroidX
后appcompat
的Fragment
变成了androidx.fragment.app
包下,原有的代码下会画红线,Android Studio
也会警告你出现错误,但是不用担心,依然可以正常编译,Android Studio
在编译的时候会自动完成基类的替换,但前提是你要确保你项目里的gradle.properties
进行了如下设置。
android.useAndroidX=true
android.enableJetifier=tru
为了消除这些难看的红线,你可以直接将新的Fragment
使用这种方式强制转换成原有的Fragment
。
TextureSupportMapFragment mapFragment = TextureSupportMapFragment
.class.cast(getChildFragmentManager()
.findFragmentById(R.id.map_view));
同理,也可以将旧的Fragment
强制类型转换成新的Fragment
.
Fragment f = Fragment.class.cast(mapFragment);
(注:上面的TextureSupportMapFragment
是一个典型案例,他是高德地图SDK
中的Fragment
,本身已经继承了v4包下的Fragment
,可以用过上面的转换来使他兼容AndroidX
)
差点扯远了,搞定AndroidX
后,我们就可以使用FragmentActivity
的addOnBackPressedCallback
方法为你的Fragment
提供拦截OnBackPressed
的功能了.
public void addOnBackPressedCallback(@NonNull LifecycleOwner owner,
@NonNull OnBackPressedCallback onBackPressedCallback)
OnBackPressedCallback#handleOnBackPressed
需要返回一个boolean
值。如果你在这个回调里拦截了onBackPressed
应该返回true
,说明你自己已经处理了本次返回键按下的操作,这样你的Fragment
就不会被弹出返回栈了。
值得注意的是,这个函数的第一个参数,一个LifecycleOwner
,Activity
和Fragment
都是LifecycleOwner
,用于提供组件的生命周期,这个参数可以帮我们自动管理OnBackPressedCallback
回调,你无需手动将他从Activity
中移除,在LifecycleOwner
的ON_DESTROY
事件来到的时候,他会被自动移除列表,你无需担心内存泄漏,框架会帮你完成这些事情。
/**
- Interface for handling {@link ComponentActivity#onBackPressed()} callbacks without
- strongly coupling that implementation to a subclass of {@link ComponentActivity}.
- @see ComponentActivity#addOnBackPressedCallback(LifecycleOwner, OnBackPressedCallback)
- @see ComponentActivity#removeOnBackPressedCallback(OnBackPressedCallback)
/
public interface OnBackPressedCallback {
/* - Callback for handling the {@link ComponentActivity#onBackPressed()} event.
- @return True if you handled the {@link ComponentActivity#onBackPressed()} event. No
- further {@link OnBackPressedCallback} instances will be called if you return true.
*/
boolean handleOnBackPressed();
}
我们可以看到Activity
内管理的OnBackPressedCallback
的执行循序与添加时间有关.最后被添加进去的能最先得到执行.
public void addOnBackPressedCallback(@NonNull LifecycleOwner owner,
@NonNull OnBackPressedCallback onBackPressedCallback) {
Lifecycle lifecycle = owner.getLifecycle();
if (lifecycle.getCurrentState() == Lifecycle.State.DESTROYED) {
// Already destroyed, nothing to do
return;
}
// Add new callbacks to the front of the list so that
// the most recently added callbacks get priority
mOnBackPressedCallbacks.add(0, new LifecycleAwareOnBackPressedCallback(
lifecycle, onBackPressedCallback));
}
可以看到它是添加到mOnBackPressedCallbacks
这个List
的最前面的.
Fragment
是必须要有id
的,使用getId
可以返回自身的id
,通常用这个方法返回它所在的容器的id
,供其他Fragment
添加进FragmentManager
时使用。(比如说你使用了一个FrameLayout
作为Fragment
的容器,那么它就会返回那个FrameLayout
的id
)
/**
- Return the identifier this fragment is known by. This is either
- the android:id value supplied in a layout or the container view ID
- supplied when adding the fragment.
*/
final public int getId() {
return mFragmentId;
}
startFragmentForResult
方法在哪?对不起和OnBackPressed
一样,Google
没有直接为我们实现这个方法,但这并不代表Fragment
没有这个功能,你当然可以直接用定义getter
的方式来获取Fragment
上内容,但这并不是最佳实践,为了规范编码我们最好还是使用公共的API
Fragment#setTargetFragment
可以给当前Fragment
设置一个目标Fragment
和一个请求码
public void setTargetFragment(@Nullable Fragment fragment, int requestCode)
当当前Fragment
完成相应的任务后,我们可以这样将返回值送回给我们的目标Fragment
通过Intent
getTargetFragment().onActivityResult(getTargetRequestCode(),
Activity.RESULT_OK,new Intent());
不过要注意,目标Fragment
和被请求的Fragment
必须在同一个FragmentManager
的管理下,否则就会报错
最后,当我们在使用Fragment#getActivity()
时返回的是一个可空值,如果没有判空检查在Android Studio
中将会出现一个恶心的黄色警告,你可以使用requireActivity()
来代替它,同样的方法还有requireFragmentManager()
等.
3.Fragment生命周期
这可能是最让人懊恼的部分之一了。下面是绝对的高能区,因为接下来的那一张图,彰显了Fragment
中最让人恐惧的一部分,它的生命周期.
本来笔者想要用ProcessOn,自己画一张Fragment
生命周期的流程图.怎么说我都是软件工程
专业的啊,最后…真香,因为这图实在是太复杂了,真要画它时间上有点过不去,所以我只好拿来主义.
下图展示了各回调发生的时间顺序:
捋一下,常用的回调有这些,觉得上面有图有点烦的话的话那就看下面总结的文字吧:
-
onInflate(Context,AttributeSet,Bundle)
只有硬编码在xml
中的Fragment
(即使用fragment
标签)才会调用该方法,与自定义View
十分类似,在实例化xml
布局时该方法会被调用 -
onAttach(Context)
执行该方法时,Fragment
与Activity
已经完成绑定,该方法传入一个Context
对象,实际上就是该Fragment
依附的Activity
,此时调用getActivity
将不会返回null
,但是Activity#onCreate
可能还有没有执行。 -
onCreate(Bundle)
用来初始化Fragment
。可通过参数savedInstanceState
获取之前保存的值。 -
onCreateView(LayoutInflater,ViewGroup,Bundle)
需要返回一个View
用来初始化Fragment
的布局。默认返回null
,值得注意的是,若返回null
Fragment#onViewCreated
将不会执行。使用ViewPager
+Fragment
时此方法可能会被多次调用。 -
onActivityCreated(Bundle)
执行该方法时,与Fragment
绑定的Activity
的onCreate
方法已经执行完成并返回,若在此之前与Activity
交互,若引用了未初始化的资源会应发空指针异常。 -
onStart()
执行该方法时,Fragment
所在的Activity
由不可见变为可见状态 -
onResume()
执行该方法时,Fragment
所在的Activity
处于活动状态,用户可与之交互 -
onPause()
执行该方法时,Fragment
所在的Activity
处于暂停状态,但依然可见,用户不能与之交互 -
onStop()
执行该方法时,Fragment
所在的Activity
完全不可见 -
onSaveInstanceState(Bundle)
保存当前Fragment
的状态。该方法会自动保存Fragment
的状态,比如EditText
键入的文本,即使Fragment
被回收又重新创建,一样能恢复EditText
之前键入的文本。 -
onDestroyView()
销毁与Fragment
有关的视图,但未与Activity
解除绑定,一般在这个回调里解除Fragment
对视图的引用。通常在ViewPager
+Fragment
的方式下会使用并重写此方法,并且与Fragment#onCreateView
一样可能是多次的。 -
onDestroy()
销毁Fragment
。通常按Back
键退出或者Fragment
被移除FragmentManager
时调用此方法,此时应该清理Fragment
中所管理的所有数据。 -
onDetach()
解除与Activity
的绑定。在onDestroy
方法之后调用。若在此时getActivity()
,你将会得到一个null
。
4.Fragment的替代方案
看了那么多有关Fragment
的介绍,如果你还对Fragment
嗤之以鼻,又想减小业务的逻辑的粒度,那么我只能给你Fragment
的替代方案了。
一位square
公司(对就是那个诞生了Retrofit
和okhttp
的公司)的工程师开发的Fragment
替代方案《View框架flow》,以及相关博文,国内有优秀的简书作者翻译了这篇文章《(译)我为什么不主张使用Fragment》,原作者在这篇文章中痛斥了Fragment
的各种缺点,我想你可能会喜欢这个.
5.结语
好了关于从Activity
迁移到Fragment
的介绍差不多就到这了,我也是想到什么就写什么,所以文章的结构可能会有些乱,以后如果还有其他知识点我会慢慢补充上来.
【附】相关架构及资料
资料及源码领取
点赞+加群免费获取 Android IOC架构设计
领取获取往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门**
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!