22
33import android .app .Activity ;
44import android .content .Context ;
5+ import android .support .annotation .NonNull ;
6+ import android .support .v4 .view .LayoutInflaterCompat ;
57import android .support .v7 .app .AppCompatActivity ;
68import android .support .v7 .app .AppCompatDelegate ;
79import android .util .AttributeSet ;
810import android .view .LayoutInflater ;
911import android .view .View ;
1012
1113import java .lang .reflect .Field ;
14+ import java .lang .reflect .InvocationTargetException ;
15+ import java .lang .reflect .Method ;
1216
1317/**
1418 * minSdkVersion最小为14,建议minSdkVersion >= 16
1519 * 如果minSdkVersion < 16:bl_gradient_angle, bl_gradient_startColor, bl_gradient_centerColor, bl_gradient_endColor会失效,其他正常
16- *
20+ * <p>
1721 * Created by xiaoqi on 2018/9/9
1822 */
1923public class BackgroundLibrary {
@@ -25,30 +29,37 @@ public static LayoutInflater inject(Context context) {
2529 } else {
2630 inflater = LayoutInflater .from (context );
2731 }
28- if (inflater == null ){
32+ if (inflater == null ) {
2933 return null ;
3034 }
31- if (inflater .getFactory2 () == null ){
32- BackgroundFactory factory = new BackgroundFactory ();
33- if (context instanceof AppCompatActivity ) {
34- final AppCompatDelegate delegate = ((AppCompatActivity ) context ).getDelegate ();
35- factory .setInterceptFactory (new LayoutInflater .Factory () {
36- @ Override
37- public View onCreateView (String name , Context context , AttributeSet attrs ) {
38- return delegate .createView (null , name , context , attrs );
39- }
40- });
41- }
35+ if (inflater .getFactory2 () == null ) {
36+ BackgroundFactory factory = setDelegateFactory (context );
4237 inflater .setFactory2 (factory );
43- }else if (!(inflater .getFactory2 () instanceof BackgroundFactory )){
44- forceSetFactory2 (inflater );
38+ } else if (!(inflater .getFactory2 () instanceof BackgroundFactory )) {
39+ forceSetFactory2 (inflater , context );
4540 }
4641 return inflater ;
4742 }
4843
44+ @ NonNull
45+ private static BackgroundFactory setDelegateFactory (Context context ) {
46+ BackgroundFactory factory = new BackgroundFactory ();
47+ if (context instanceof AppCompatActivity ) {
48+ final AppCompatDelegate delegate = ((AppCompatActivity ) context ).getDelegate ();
49+ factory .setInterceptFactory (new LayoutInflater .Factory () {
50+ @ Override
51+ public View onCreateView (String name , Context context , AttributeSet attrs ) {
52+ return delegate .createView (null , name , context , attrs );
53+ }
54+ });
55+ }
56+ return factory ;
57+ }
58+
4959 /**
5060 * used for activity which has addFactory
5161 * 如果因为其他库已经设置了factory,可以使用该方法去进行inject,在其他库的setFactory后面调用即可
62+ *
5263 * @param context
5364 */
5465 public static LayoutInflater inject2 (Context context ) {
@@ -58,32 +69,64 @@ public static LayoutInflater inject2(Context context) {
5869 } else {
5970 inflater = LayoutInflater .from (context );
6071 }
61- if (inflater == null ){
72+ if (inflater == null ) {
6273 return null ;
6374 }
64- forceSetFactory2 (inflater );
75+ forceSetFactory2 (inflater , context );
6576 return inflater ;
6677 }
6778
68- private static void forceSetFactory2 (LayoutInflater inflater ) {
79+ /**
80+ * 通过LayoutInflaterCompat去规避非SDK接口在Android Q 中的受限。
81+ * 首先:设置LayoutInflaterCompat的sCheckedField为false, 保证可以设置当前mFactory2的值
82+ * 第二:设置LayoutInflater的 mFactory 为空,保证LayoutInflaterCompat调用setFactory的时候不进行FactoryMerger操作
83+ * 第三:反射调用LayoutInflaterCompat的forceSetFactory2方法
84+ * 第四:重新设置LayoutInflater的mFactory值,防止调用Fragment的时候fragment会进行FactoryMerger操作
85+ * 经过上述步骤,在Activity以及Activity中的Fragment就会变成我们想要的factory类
86+ */
87+ private static void forceSetFactory2 (LayoutInflater inflater , Context context ) {
88+ Class <LayoutInflaterCompat > compatClass = LayoutInflaterCompat .class ;
89+ Class <LayoutInflater > inflaterClass = LayoutInflater .class ;
6990 try {
70- Field field = LayoutInflater .class .getDeclaredField ("mFactorySet" );
71- field .setAccessible (true );
72- field .setBoolean (inflater , false );
91+ Field sCheckedField = compatClass .getDeclaredField ("sCheckedField" );
92+ sCheckedField .setAccessible (true );
93+ sCheckedField .setBoolean (inflater , false );
94+ Field mFactory = inflaterClass .getDeclaredField ("mFactory" );
95+ mFactory .setAccessible (true );
96+ mFactory .set (inflater , null );
7397
74- BackgroundFactory factory = new BackgroundFactory ();
75- if (inflater .getFactory2 () != null ) {
76- factory .setInterceptFactory2 (inflater .getFactory2 ());
77- } else if (inflater .getFactory () != null ) {
78- factory .setInterceptFactory (inflater .getFactory ());
79- }
80- inflater .setFactory2 (factory );
81- } catch (NoSuchFieldException e ) {
82- e .printStackTrace ();
83- } catch (IllegalArgumentException e ) {
98+ Method method = compatClass .getDeclaredMethod ("forceSetFactory2" , LayoutInflater .class , LayoutInflater .Factory2 .class );
99+ method .setAccessible (true );
100+ BackgroundFactory factory = setDelegateFactory (context );
101+ method .invoke (null , inflater , factory );
102+ mFactory .set (inflater , factory );
103+ } catch (NoSuchMethodException e ) {
84104 e .printStackTrace ();
85105 } catch (IllegalAccessException e ) {
86106 e .printStackTrace ();
107+ } catch (InvocationTargetException e ) {
108+ e .printStackTrace ();
109+ } catch (NoSuchFieldException e ) {
110+ e .printStackTrace ();
87111 }
112+ // try {
113+ // Field field = LayoutInflater.class.getDeclaredField("mFactorySet");
114+ // field.setAccessible(true);
115+ // field.setBoolean(inflater, false);
116+ //
117+ // BackgroundFactory factory = new BackgroundFactory();
118+ // if (inflater.getFactory2() != null) {
119+ // factory.setInterceptFactory2(inflater.getFactory2());
120+ // } else if (inflater.getFactory() != null) {
121+ // factory.setInterceptFactory(inflater.getFactory());
122+ // }
123+ // inflater.setFactory2(factory);
124+ // } catch (NoSuchFieldException e) {
125+ // e.printStackTrace();
126+ // } catch (IllegalArgumentException e) {
127+ // e.printStackTrace();
128+ // } catch (IllegalAccessException e) {
129+ // e.printStackTrace();
130+ // }
88131 }
89132}
0 commit comments