Is there an Android tool to find the name of a layout for a running app?

后端 未结 7 1583
刺人心
刺人心 2021-02-07 03:37

Background

I have been recently hired to maintain a very large program (only two Activities, about a hundred Fragments, and several hundred layouts).

7条回答
  •  夕颜
    夕颜 (楼主)
    2021-02-07 04:09

    Inspired by @nekocode ResourceInspector, I figure out how to show the layout resource name in the screenshot captured by AS's layout inspector.

    Firstly create a class LayoutIndicatorInflater

    public class LayoutIndicatorInflater extends LayoutInflater {
    
        private LayoutInflater mOriginalInflater;
        private String mAppPackageName;
    
        protected LayoutIndicatorInflater(LayoutInflater original, Context newContext) {
            super(original, newContext);
            mOriginalInflater = original;
            mAppPackageName = getContext().getPackageName();
        }
    
        @Override
        public LayoutInflater cloneInContext(Context newContext) {
            return new LayoutIndicatorInflater(mOriginalInflater.cloneInContext(newContext), newContext);
        }
    
        @Override
        public void setFactory(Factory factory) {
            super.setFactory(factory);
            mOriginalInflater.setFactory(factory);
        }
    
        @Override
        public void setFactory2(Factory2 factory) {
            super.setFactory2(factory);
            mOriginalInflater.setFactory2(factory);
        }
    
        @Override
        public View inflate(int resourceId, ViewGroup root, boolean attachToRoot) {
            Resources res = getContext().getResources();
    
            String packageName = "";
            try {
                packageName = res.getResourcePackageName(resourceId);
            } catch (Exception e) {}
    
    
            String resName = "";
            try {
                resName = res.getResourceEntryName(resourceId);
            } catch (Exception e) {}
    
            View view = mOriginalInflater.inflate(resourceId, root, attachToRoot);
    
            if (!mAppPackageName.equals(packageName)) {
                return view;
            }
    
            View targetView = view;
            if (root != null && attachToRoot) {
                targetView = root.getChildAt(root.getChildCount() - 1);
            }
    
            targetView.setContentDescription("layout res:" + resName);
    
            if (targetView instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) targetView;
                for (int i = 0; i < viewGroup.getChildCount(); i++) {
                    View child = viewGroup.getChildAt(i);
                    if (TextUtils.isEmpty(child.getContentDescription())) {
                        child.setContentDescription("layout res:" + resName);
                    }
                }
            }
    
            return view;
        }
    }
    

    Then create a helper class

        public class LayoutIndicatorHelper {
    
        public static void init(Application application) {
            if (BuildConfig.DEBUG) {
                application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                        try {
                            Field inflaterField = ContextThemeWrapper.class.getDeclaredField("mInflater");
                            inflaterField.setAccessible(true);
                            LayoutInflater inflater = (LayoutInflater) inflaterField.get(activity);
                            LayoutInflater proxyInflater = null;
                            if (inflater != null) {
                                proxyInflater = new LayoutIndicatorInflater(inflater, activity);
                                inflaterField.set(activity, proxyInflater);
                            }
    
                            Class phoneWindowClass = Class.forName("com.android.internal.policy.PhoneWindow");
                            Field phoneWindowInflater = phoneWindowClass.getDeclaredField("mLayoutInflater");
                            phoneWindowInflater.setAccessible(true);
                            inflater = (LayoutInflater) phoneWindowInflater.get(activity.getWindow());
                            if (inflater != null && proxyInflater != null) {
                                phoneWindowInflater.set(activity.getWindow(), proxyInflater);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
    
                    @Override
                    public void onActivityStarted(Activity activity) {
    
                    }
    
                    @Override
                    public void onActivityResumed(Activity activity) {
    
                    }
    
                    @Override
                    public void onActivityPaused(Activity activity) {
    
                    }
    
                    @Override
                    public void onActivityStopped(Activity activity) {
    
                    }
    
                    @Override
                    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    
                    }
    
                    @Override
                    public void onActivityDestroyed(Activity activity) {
    
                    }
                });
            }
        }
    
    }
    

    Finally call LayoutIndicatorHelper.init in your Application's onCreate

        public class MyApplication extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            LayoutIndicatorHelper.init(this);
        }
    }
    

提交回复
热议问题