Фон: Когда объём кода проекта большой, или когда нужно быстро разобраться в коде новому человеку, добавление логов для понимания логики выполнения кода может быть слишком затратным, так как требует изменения компиляции и запуска проекта. Это может занять много времени. Или же можно попробовать отладить несколько функций, чтобы понять логику выполнения кода, но есть риск пропустить некоторые функции.
Можно, конечно, упрямо добавить логирование во весь код, который вы написали, но это не решит проблему с отслеживанием порядка вызова функций из сторонних библиотек или Android SDK.
Решение: В этом проекте предлагается использовать пакетные имена в качестве фильтра для отслеживания порядка вызовов всех функций.
Примечание: Автор текста и связанных библиотек просит указывать ссылку на оригинальный текст при его использовании.
Проект доступен по адресу: https://github.com/zjw-swun/AppMethodOrder.
На рисунке показан пример использования библиотеки. Сначала пользователь нажимает на пользовательский MyTextView
в MainActivity
, затем переходит к SecondActivity
, где также нажимает на textview
, после чего возвращается к MainActivity
.
Библиотека обрабатывает полученный порядок вызовов функций и сохраняет его в файле order.txt
. В данном случае автор скрыл функции из JDK, сторонних библиотек и Android SDK, оставив только порядок вызова функций в своём пакете.
Вот часть содержимого файла order.txt
:
832 ent 67593 .....com.zjw.appmethodorder.MainActivity.onClick (Landroid/view/View;)V MainActivity.java
832 ent 99956 ..........com.zjw.appmethodorder.MainActivity.onPause ()V MainActivity.java
...
832 ent 4539467 ..........com.zjw.appmethodorder.BaseActivity.onResume ()V BaseActivity.java
``` ```
@Override
public int compareTo(Sort o) {
// TODO Auto-generated method stub
//return 0;
return (int) (Long.valueOf(str) - Long.valueOf(o.str));
}
В результате было обнаружено, что последовательность элементов после фильтрации соответствует их порядковым номерам, но не логической последовательности выполнения кода. Автор столкнулся с проблемой получения некорректного результата при использовании инструментального кода и обнаружил, что опция dmtracedump -ho позволяет выводить содержимое в логическом порядке сверху вниз. На основе этого автор разработал проект, целью которого является понимание порядка вызова всех функций.
//Задача проекта: вывод информации о порядке вызова функций на основе файла trace в текстовом формате в каталоге captures
task AppOutPutMethodOrder() {
doLast {
def capturesDirPath = project.getProjectDir().getParentFile().path + File.separator + "captures";
def capturesDir = file(capturesDirPath);
def traceType = "trace"
if (!capturesDir.exists() || !capturesDir.canRead()) {
return
}
def map = new TreeMap<Long, String>(
new Comparator<Long>() {
public int compare(Long obj1, Long obj2) {
return obj2.compareTo(obj1);
}
});
//Перебираем имена файлов в каталоге, находим файл с наибольшим временем и получаем строку
capturesDir.list(new FilenameFilter() {
@Override
boolean accept(File dir, String name) {
if (name.contains(traceType)) {
def substring = name.substring(name.length() - 22, name.length() - 6).trim()
String regEx = "[^0-9]"
Pattern p = Pattern.compile(regEx)
Matcher m = p.matcher(substring)
def time = m.replaceAll("").trim()
map.put(Long.parseLong(time), name)
}
return false
}
})
def lastTraceName = "";
Set<Long> keySet = map.keySet();
Iterator<Long> iterator = keySet.iterator();
while (iterator.hasNext()) {
Long key = iterator.next();
lastTraceName = map.get(key);
break;
}
def tracePath = capturesDirPath + File.separator + lastTraceName
println "===== tracePath is ${tracePath} =========="
def orderPath = capturesDirPath + File.separator + "base_order.txt"
def orderFile = file(orderPath)
if(orderFile.exists()){
orderFile.write("")
}
Runtime runtime = Runtime.getRuntime();
//dmtracedump — это инструмент из Android SDK, для его использования нужно добавить переменную среды
def baseComand = "dmtracedump -ho " + tracePath + " >> " + orderPath
def command = ""
String[] cmdArray = null;
String osName = System.getProperty("os.name");
String osNameMatch = osName.toLowerCase();
if(osNameMatch.contains("windows")) {
command = "cmd /c start /b "+baseComand;
}else {
cmdArray = ["bash", "-c", baseComand];
}
try {
if (cmdArray != null) {
runtime.exec(cmdArray);
} else {
runtime.exec(command);
}
} catch (Exception e) {
println "=====Exception: ${e.getCause()} =========="
}
}
}
//Здесь задача AppFilterMethodOrder фактически не нужна, она просто находит файл base_order.txt в каталоге \captures
//Для фильтрации используется Notepad++, применяются регулярные выражения для удаления строк, содержащих xit (обозначает выход из функции), а также ненужных пакетов
//Используемые команды в Notepad++:
//^.*xit.*$ //удаляет строки, содержащие xit
// ^((?!XXX).)*$ //удаляет строки без XXX
//^\s+ //объединяет пустые строки
task AppFilterMethodOrder(){
doLast{
def capturesDirPath = project.getProjectDir().getParentFile().path + File.separator + "captures";
def orderPath = capturesDirPath + File.separator + "base_order.txt"
if(!file(orderPath).exists()){
return
}
BufferedReader inputStream = new BufferedReader(new FileReader(orderPath));
def filterOrderPath = new File(capturesDirPath + File.separator + "order.txt")
if (!filterOrderPath.exists()){
filterOrderPath.createNewFile();
}else {
filterOrderPath.write("")
}
String content ;
while ((content = inputStream.readLine()) != null) {
``` ```
# 3. Как использовать
Мы рассказали о принципах работы, теперь давайте поговорим о том, как использовать эту библиотеку.
Сначала скомпилируйте и запустите проект. Затем нажмите на часы на следующем рисунке (это инструмент для trace start и end). Вы можете обратиться к введению о действиях (помните, что вы должны подумать о порядке вызова функций жизненного цикла, а затем сравнить его с порядком функций в файлах base_order.txt или order.txt, которые были созданы в каталоге captures). После этого снова нажмите на часы.
Есть ещё один способ записать trace start и end — это использование android.os.Debug.startMethodTracing(); и android.os.Debug.stopMethodTracing().
После выполнения этих действий в каталоге captures будет создан файл com.zjw.appmethodorder_2017.03.25_21.41.trace. Android Studio откроет окно визуализации по умолчанию.
Затем дважды щёлкните AppOutPutMethodOrder на правой панели, как показано на рисунке ниже.
На этом этапе в каталоге captures создаётся файл base_order.txt, который содержит порядок выполнения всех функций.
Дождитесь завершения задачи, затем выполните задачу AppFilterMethodOrder, как показано ниже.
Цель этой задачи — отфильтровать другие имена пакетов, оставив только функции из вашего пакета. После выполнения задачи в каталоге captures создастся файл order.txt.
Откройте файл order.txt — и вы увидите результат, описанный ранее.
# 4. О расширении и модификации
Здесь можно внести небольшие изменения. Обратите внимание, что AppOutPutMethodOrder всегда использует последний файл .trace для создания base_order.txt в качестве эталона.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )