Существует ли инструмент Android, чтобы найти название макета для работающего приложения?

Фон

Меня недавно наняли для работы с очень большой программой (только два вида деятельности, около ста фрагментов и несколько сотен макетов). Кроме того, большая часть содержимого макетов (изображений и текста), а также порядок их отображения динамически определяются через веб-API компании.

К сожалению, нет документации. Нет карты, нада. Компания наняла стороннего производителя для создания этого приложения задолго до того, как у них появились программисты на Android. И качество кода в лучшем случае плохое (даже имена переменных сбивают с толку и противоречивы).

Следовательно, я трачу около 70% - 90% своего времени на простой поиск макетов и кода, просто чтобы изменить фон кнопки.

Вопрос

Есть ли инструмент, который можно запустить (возможно, в отладчике Android Studio?), Который может каким-то образом выплевывать имена файлов макета, которые отображаются в данный момент?

Мои начальники часто говорят что-то вроде: "Измените текстуру фона с черного на светло-серый". И я думаю: изменение тривиально, но поиск XML-файла может занять час.

--Обновить--

Проект, который породил этот вопрос, больше не находится под моим контролем, поэтому этот вопрос стал спорным. Но, похоже, это общая проблема, поэтому я оставляю этот вопрос открытым. Возможно, в будущем появится какой-нибудь инструмент / решение. Я надеюсь, что эта тема будет полезна для других программистов в этой ситуации.

7 ответов

Существует также приложение Developer Assistant для Android, которое может проверять иерархию представлений во время выполнения и затем отображать наиболее вероятные имена макетов, видимые на экране. Эвристика включена, поэтому она не будет работать на 100% с точностью, но все же может быть полезна и работает полностью в автономном режиме (раскрытие: я сделал это приложение).

Пример:

введите описание изображения здесь

Инструмент просмотра иерархии

В Android Device Monitor есть кнопка, которую вы можете нажать, которая называется "Иерархия просмотра дампа для UI Automator".

Это откроет просмотрщик иерархии пользовательского интерфейса в мониторе устройств, который можно использовать для просмотра идентификаторов ресурсов каждого из ваших представлений.

Хотя на самом деле это не дает вам имя завышенного XML-файла, это может быть очень полезно. Если вам повезет, вы можете даже использовать идентификаторы ресурсов, чтобы сузить поиск файлов XML для поиска.

И если вы наведете указатель мыши на заголовок окна программы просмотра, он покажет вам путь к фактическому XML-файлу, который он создал. Это способ найти все идентификаторы ресурсов в одном месте.


Еще немного информации о Hierarchy Viewer на случай, если это поможет:

Средство просмотра иерархии позволяет отлаживать и оптимизировать пользовательский интерфейс. Он обеспечивает визуальное представление иерархии представления макета (представление макета) и увеличенный инспектор дисплея (представление Pixel Perfect).


Создать пользовательский макет Inflater в коде

Вот запись в блоге, которая содержит что-то интересное - пользовательский макет, который перехватывает всю инфляцию представления:

Может быть возможно использовать этот пример кода для перехвата раздуваемых вызовов и получения идентификатора ресурса файла XML:

На этом этапе вам нужно будет превратить идентификатор ресурса в полезное имя. Цитируя этот вопрос ( Как получить имя ресурса из идентификатора ресурса), вы можете использовать:

getResources().getResourceEntryName(int resid);

Добавьте некоторую регистрацию, и это может дать вам каждый файл XML по мере его надувания.

Это может быть хорошим способом документировать весь ваш проект.

Возможно "Android/sdk/tools/uiautomatorviewer" может вам помочь. Он может получить дамп текущего экрана с устройства и показать вам виды / макеты с их деталями - также с идентификаторами

Вы можете попробовать этот инструмент: https://github.com/nekocode/ResourceInspector

Он может проверять все используемые файлы макетов текущей деятельности.

Начиная с версии Android 3.0 и выше, инструмент просмотра иерархии устарел. Есть автономный LayoutInspector, Вы можете получить к нему доступ, нажав на инструменты в верхней панели Android Studio.

Вдохновленный @nekocode ResourceInspector, я выяснил, как показать имя ресурса макета на скриншоте, снятом инспектором макетов AS. показать имя ресурса макета на скриншоте, снятом инспектором макета AS

Сначала создайте класс 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;
    }
}

Затем создайте вспомогательный класс

    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) {

                }
            });
        }
    }

}

Наконец позвони LayoutIndicatorHelper.init в вашем Application"s onCreate

    public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        LayoutIndicatorHelper.init(this);
    }
}

Возможно, это слишком поздно, но мой ответ могут использовать разные программисты.

Библиотека Stetho в Facebook - это замечательный инструмент для проверки работоспособности приложений. Библиотека Stetho работает как расширение Chrome и будет похожа для многих программистов.

Кроме того, увидеть HTTP-запрос / ответы очень легко с помощью Stetho. Я абсолютно советую каждому программисту Android попробовать.

http://facebook.github.io/stetho/

Другие вопросы по тегам