Skip to content

Commit 6479566

Browse files
committed
迁移到 AndroidX
1 parent 25d103a commit 6479566

File tree

106 files changed

+467
-461
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+467
-461
lines changed

Details-en.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,17 @@ public final class XxxActivity extends AppCompatActivity {
198198

199199
5. `FragmentActivity extends ComponentActivity extends Activity`
200200

201-
* This creates a problem: some permission request frameworks use a transparent `Fragment` to get permission request callbacks. If the permission request framework uses `android.support.v4.app.Fragment`, then it must require the outer layer to pass in an `android.support.v4.app.FragmentActivity` object. If the `Activity` you're using is not a subclass of `android.support.v4.app.FragmentActivity`, what should you do? Simple, you might say, just modify the current `Activity` to directly inherit from `android.support.v4.app.FragmentActivity`, right? But what if your current `Activity` must inherit from `FlutterActivity`, `ComposeActivity`, `UnityPlayerActivity`, or `Cocos2dxActivity`? What should you do then? Modify their source code? Or modify the permission framework's source code? Whichever solution you choose, the cost of adaptation will be very high and difficult to maintain in the future. This is neither realistic nor scientific. Do you suddenly feel like heaven has blocked your path? Is writing permission request API code by hand the only way to implement permission requests?
201+
* This creates a problem: some permission request frameworks use a transparent `Fragment` to get permission request callbacks. If the permission request framework uses `androidx.fragment.app.Fragment`, then it must require the outer layer to pass in an `androidx.fragment.app.FragmentActivity` object. If the `Activity` you're using is not a subclass of `androidx.fragment.app.FragmentActivity`, what should you do? Simple, you might say, just modify the current `Activity` to directly inherit from `androidx.fragment.app.FragmentActivity`, right? But what if your current `Activity` must inherit from `FlutterActivity`, `ComposeActivity`, `UnityPlayerActivity`, or `Cocos2dxActivity`? What should you do then? Modify their source code? Or modify the permission framework's source code? Whichever solution you choose, the cost of adaptation will be very high and difficult to maintain in the future. This is neither realistic nor scientific. Do you suddenly feel like heaven has blocked your path? Is writing permission request API code by hand the only way to implement permission requests?
202202

203-
* Actually, the framework has already thought of this problem and has solved it for you without requiring any handling on your part. The specific implementation principle is: the framework will determine if the `Activity` object you pass in is a subclass of `android.support.v4.app.FragmentActivity`. If it is, it will use `android.support.v4.app.Fragment` for permission requests; if not, it will use `android.app.Fragment` for permission requests. This way, no matter which type of `Activity` you use, the framework can automatically adapt.
203+
* Actually, the framework has already thought of this problem and has solved it for you without requiring any handling on your part. The specific implementation principle is: the framework will determine if the `Activity` object you pass in is a subclass of `androidx.fragment.app.FragmentActivity`. If it is, it will use `androidx.fragment.app.Fragment` for permission requests; if not, it will use `android.app.Fragment` for permission requests. This way, no matter which type of `Activity` you use, the framework can automatically adapt.
204204

205205
#### Callback Lifecycle Synchronized with Host
206206

207-
* Most permission request frameworks on the market use a single type of `Fragment` to handle permission request callbacks, but this leads to a problem. Suppose a framework uses `android.support.v4.app.Fragment` to handle permission request callbacks, but you initiated the permission request in `android.app.Fragment`, or vice versa, you used `android.support.v4.app.Fragment` but the framework used `android.app.Fragment`. You can't pass your own `Fragment` as the host to the permission request framework; you can only pass the `Activity` object to the framework through `fragment.getActivity()`. This makes the `Activity` the host object, leading to a lifecycle asynchronization problem: your own `Fragment` may have been destroyed, but the framework will still callback the permission request result listener, causing `Memory leak` at best and triggering `Exception` at worst.
207+
* Most permission request frameworks on the market use a single type of `Fragment` to handle permission request callbacks, but this leads to a problem. Suppose a framework uses `androidx.fragment.app.Fragment` to handle permission request callbacks, but you initiated the permission request in `android.app.Fragment`, or vice versa, you used `androidx.fragment.app.Fragment` but the framework used `android.app.Fragment`. You can't pass your own `Fragment` as the host to the permission request framework; you can only pass the `Activity` object to the framework through `fragment.getActivity()`. This makes the `Activity` the host object, leading to a lifecycle asynchronization problem: your own `Fragment` may have been destroyed, but the framework will still callback the permission request result listener, causing `Memory leak` at best and triggering `Exception` at worst.
208208

209209
* The reason for this problem is that the `Fragment` used by the third-party framework and your `Fragment` are not actually the same type. Although they have the same class name, they are in different packages. Plus, as just mentioned, you can only pass the `Activity` object to the framework through `fragment.getActivity()`, so your own `Fragment` cannot form an effective lifecycle binding with the framework's `Fragment`. What you actually want is to bind to your own `Fragment`'s lifecycle, but the framework ultimately binds to the `Activity`'s lifecycle, which can easily trigger a crash. You can see the specific manifestation in this issue: [XXPermissions/issues/365](https://github.com/getActivity/XXPermissions/issues/365).
210210

211-
* Actually, the framework has already thought of this problem and has solved it for you without requiring any handling on your part. The approach to solving this problem is: the framework will automatically select the best type of `Fragment` based on the type of object you pass in. If the host you pass in is an `android.support.v4.app.FragmentActivity` or `android.support.v4.app.Fragment` object, the framework will internally create an `android.support.v4.app.Fragment` to receive permission request callbacks. If the host you pass in is a regular `Activity` or `android.app.Fragment`, the framework will internally create an `android.app.Fragment` to receive permission request callbacks. This way, no matter what host object you pass in, the framework will bind to its lifecycle, ensuring that when the permission request result is called back to the outermost layer, the host object is still in a normal state.
211+
* Actually, the framework has already thought of this problem and has solved it for you without requiring any handling on your part. The approach to solving this problem is: the framework will automatically select the best type of `Fragment` based on the type of object you pass in. If the host you pass in is an `androidx.fragment.app.FragmentActivity` or `androidx.fragment.app.Fragment` object, the framework will internally create an `androidx.fragment.app.Fragment` to receive permission request callbacks. If the host you pass in is a regular `Activity` or `android.app.Fragment`, the framework will internally create an `android.app.Fragment` to receive permission request callbacks. This way, no matter what host object you pass in, the framework will bind to its lifecycle, ensuring that when the permission request result is called back to the outermost layer, the host object is still in a normal state.
212212

213213
* At this point, you might jump in and say, I can implement this without the framework. I can manually check the `Fragment`'s state in the permission callback method. Isn't it just a matter of two or three lines of code? Why does the framework make it so complicated? Your idea seems reasonable but doesn't stand up to scrutiny. If your project requests permissions in a dozen places, you would need to consider this issue in every callback method. Additionally, when requesting new permissions in the future, you would also need to consider this issue. Can you ensure that you won't miss anything when making changes? And what if this requirement was developed by your colleague, but only you know about this issue, and they are unaware? Do you know what might happen in that case? I believe you understand better than I do. The solution you provided, although it can temporarily solve the problem, treats the symptoms but not the root cause. The fundamental issue is that the approach to solving the problem is flawed, following a patch-the-hole mentality rather than thinking about blocking the leak at the source. Or perhaps you already knew how to completely cure it but chose the easiest way to handle it, which undoubtedly plants a time bomb in the project.
214214

Details-zh.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,17 +210,17 @@ public final class XxxActivity extends AppCompatActivity {
210210

211211
5. `FragmentActivity extends ComponentActivity extends Activity`
212212

213-
* 这样就会出现一个问题,有些权限请求框架是用一个透明的 `Fragment` 获得权限申请的回调,如果这个权限请求框架用的是 `android.support.v4.app.Fragment`,那么就必须要求外层传入 `android.support.v4.app.FragmentActivity` 对象,假设这个时候你用的 `Activity` 并不是 `android.support.v4.app.FragmentActivity` 的子类,请问你该怎么办?那简单,我就修改当前 `Activity` 直接继承 `android.support.v4.app.FragmentActivity` 不就行了?那如果你目前的 `Activity` 是一定要继承 `FlutterActivity``ComposeActivity``UnityPlayerActivity``Cocos2dxActivity` 呢?请问你又该怎么改?难不成去改它们的源码?还是去改权限框架的源码?无论选哪种解决方案,改造的成本都会很大,后续也不好维护,这既不现实,也不科学。是不是突然感觉上天把路给你堵死了?难不成只能手写权限申请 API 的代码才能实现权限请求了?
213+
* 这样就会出现一个问题,有些权限请求框架是用一个透明的 `Fragment` 获得权限申请的回调,如果这个权限请求框架用的是 `androidx.fragment.app.Fragment`,那么就必须要求外层传入 `androidx.fragment.app.FragmentActivity` 对象,假设这个时候你用的 `Activity` 并不是 `androidx.fragment.app.FragmentActivity` 的子类,请问你该怎么办?那简单,我就修改当前 `Activity` 直接继承 `androidx.fragment.app.FragmentActivity` 不就行了?那如果你目前的 `Activity` 是一定要继承 `FlutterActivity``ComposeActivity``UnityPlayerActivity``Cocos2dxActivity` 呢?请问你又该怎么改?难不成去改它们的源码?还是去改权限框架的源码?无论选哪种解决方案,改造的成本都会很大,后续也不好维护,这既不现实,也不科学。是不是突然感觉上天把路给你堵死了?难不成只能手写权限申请 API 的代码才能实现权限请求了?
214214

215-
* 其实这个问题框架已经想到了,并且已经帮你解决了,无需你做任何处理,具体的实现原理是:框架会判断你传入的 `Activity` 对象是不是 `android.support.v4.app.FragmentActivity` 的子类,如果是的话,则会用 `android.support.v4.app.Fragment` 进行权限申请,如果不是的话,则会用 `android.app.Fragment` 进行权限申请,这样无论你用哪种 `Activity`,框架都能自动进行适配。
215+
* 其实这个问题框架已经想到了,并且已经帮你解决了,无需你做任何处理,具体的实现原理是:框架会判断你传入的 `Activity` 对象是不是 `androidx.fragment.app.FragmentActivity` 的子类,如果是的话,则会用 `androidx.fragment.app.Fragment` 进行权限申请,如果不是的话,则会用 `android.app.Fragment` 进行权限申请,这样无论你用哪种 `Activity`,框架都能自动进行适配。
216216

217217
#### 回调生命周期与宿主保持同步
218218

219-
* 目前市面上大多数权限请求框架都会用单种 `Fragment` 处理权限请求回调,但是这样会导致一个问题,假设某个框架用的是 `android.support.v4.app.Fragment` 处理权限请求回调,但是你却是在 `android.app.Fragment` 发起的权限请求,又或者反过来,你用 `android.support.v4.app.Fragment` 框架用 `android.app.Fragment`,你无法把你自己的 `Fragment` 当做宿主,然后传给权限请求框架,只能通过 `fragment.getActivity()``Activity` 对象传给框架,这样 `Activity` 就成了宿主对象,这样都会导致一个生命周期不同步的问题,就是你自己的 `Fragment` 已经销毁的情况,但是框架仍会回调权限请求结果的监听器,轻则导致 `Memory leak`,重则会触发 `Exception`
219+
* 目前市面上大多数权限请求框架都会用单种 `Fragment` 处理权限请求回调,但是这样会导致一个问题,假设某个框架用的是 `androidx.fragment.app.Fragment` 处理权限请求回调,但是你却是在 `android.app.Fragment` 发起的权限请求,又或者反过来,你用 `androidx.fragment.app.Fragment` 框架用 `android.app.Fragment`,你无法把你自己的 `Fragment` 当做宿主,然后传给权限请求框架,只能通过 `fragment.getActivity()``Activity` 对象传给框架,这样 `Activity` 就成了宿主对象,这样都会导致一个生命周期不同步的问题,就是你自己的 `Fragment` 已经销毁的情况,但是框架仍会回调权限请求结果的监听器,轻则导致 `Memory leak`,重则会触发 `Exception`
220220

221221
* 导致这个问题的原因是,第三方框架用的 `Fragment` 和你的 `Fragment` 实际上不是一个类型的,虽然它们的类名一样,但是它们所在的包名不一样,加上刚刚说的你只能通过 `fragment.getActivity()``Activity` 对象传给框架,这样你自己的 `Fragment` 无法和框架的 `Fragment` 之间无法形成一种有效的生命周期绑定,实际你想要的是绑定你自己 `Fragment` 的生命周期,但框架最终绑定的是 `Activity` 生命周期,这样很可能会触发 Crash,具体表现你可以看一下这个 issue:[XXPermissions/issues/365](https://github.com/getActivity/XXPermissions/issues/365)
222222

223-
* 其实这个问题框架已经想到了,并且已经帮你解决了,无需你做任何处理,解决这个问题的思路是:框架会根据你传入的对象类型,自动选择最佳类型的 `Fragment`,假设你传入的宿主是 `android.support.v4.app.FragmentActivity` 或者 `android.support.v4.app.Fragment` 对象,框架内部则会创建 `android.support.v4.app.Fragment` 来接收权限请求回调,假设你传入的宿主是普通的 `Activity` 或者 `android.app.Fragment`,框架内部则会创建 `android.app.Fragment` 来接收权限请求回调,这样无论你传入的是什么宿主对象,框架都会和它的生命周期做绑定,确保在回调权限请求结果给到最外层的时候,宿主对象仍处于正常的状态。
223+
* 其实这个问题框架已经想到了,并且已经帮你解决了,无需你做任何处理,解决这个问题的思路是:框架会根据你传入的对象类型,自动选择最佳类型的 `Fragment`,假设你传入的宿主是 `androidx.fragment.app.FragmentActivity` 或者 `androidx.fragment.app.Fragment` 对象,框架内部则会创建 `androidx.fragment.app.Fragment` 来接收权限请求回调,假设你传入的宿主是普通的 `Activity` 或者 `android.app.Fragment`,框架内部则会创建 `android.app.Fragment` 来接收权限请求回调,这样无论你传入的是什么宿主对象,框架都会和它的生命周期做绑定,确保在回调权限请求结果给到最外层的时候,宿主对象仍处于正常的状态。
224224

225225
* 这个时候你可能会跳出来说,这个不用框架我也能实现,我自己在权限回调的方法中,自己手动判断一下 `Fragment` 的状态不就行了?不就是两三句代码的事情?框架为什么搞得那么麻烦?你的想法看似有道理,但实则经不起推敲,假设你的项目有十几处地方申请了权限,那么你需要在每个回调方法都考虑这个问题,另外后续申请新的权限,你也要考虑这个问题,你能确保自己改的时候不会出现漏网之鱼?还有假设这个需求是你的同事开发的,但是只有你知道这个事情,他并不知情的情况下,你知道这种情况下可能会发生什么吗?我相信你比我更懂。你提供的解决问题方法,虽然可以暂时解决问题,但是治标不治本,究其根本是解决的思路有问题,遵循的是有洞补洞的思维,而没有想从源头堵住漏洞。又或者你原本就知道怎么彻底根治,只不过选择了最轻松的方式来处理,但这无疑是给项目埋了一颗定时炸弹。
226226

0 commit comments

Comments
 (0)