最后
针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
/**
- Called when the hidden state (as returned by {@link #isHidden()} of
- the fragment has changed. Fragments start out not hidden; this will
- be called whenever the fragment changes state from that.
- @param hidden True if the fragment is now hidden, false otherwise.
*/
public void onHiddenChanged(boolean hidden) {
}
Fragment
有两种方式生成,一是硬编码到xml
文件中,二是在Java
代码中new
,然后通过FragmentManager#beginTransaction
开启FragmentTransaction
提交来添加Fragment
(下文会介绍).两种方式存在着一定区别.硬编码到xml
的Fragment
无法被FragmentTransition#remove
移除,与Activity
同生共死,所以你要是这么用了,就不用试了,移除不了的,但是在代码中new
出来的是可以被移除的.
硬编码到xml
中:
添加Fragment
的第二种方式就是使用FragmentManager#beginTransaction
(代码如下)动态添加,你需要先new
一个Fragment
,然后通过下面Fragment#requireFragmentManager
获取FragmentManager
来使用beginTransaction
添加Fragment
,注意add
方法的第一个参数,你需要给它指定一个id
,也就是Fragment
容器的id
,通常容器是一个没有子View
的FrameLayout
,它决定了Fragment
要在什么位置显示。
需要注意的是FragmentTransaction
并不是立即执行的,而是在当前代码执行完毕后,回到事件循环(也就是你们知道的Looper
)时,才会执行,不过他会保证在下一帧渲染之前得到执行(通过Handler#createAsync
机制),若要在FragmentTransaction
执行时搞事情,你需要使用runOnCommit
,下面的代码中我使用了Java8
的lambda
表达式简写了Runnable
.
若要使用Fragment
回退栈记得addToBackStack
,最后别忘了commit
,这样才会生效,此时commit
函数返回的是BackStackEntry
的id
requireFragmentManager()
.beginTransaction()
.add(id, fragment)
.runOnCommit(()->{/TODO/})
.addToBackStack(null)
.commit();
当然FragmentTransaction
不止可以执行add
操作,同样也可以执行remove
,show
,hide
等操作.
这里插入一个简短的题外话作为上面知识的补充。如何在Android Studio
中启用Java8
?在你模块的build.gradle
中
android{
//省略…
//加上下面的脚本代码,然后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)
最后
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!