android-studio - Android studio logcat 没什么可显示的

2025-06-13 07:10:15 by admin u19世界杯

当其他一切都不起作用时,这就是我所做的。由于adb logcat工作得很好,我决定依靠它。在 Android Studio 的嵌入式终端中运行adb logcat -v color会产生类似于普通 logcat 的输出,并且允许代码链接也可以工作:

但这带来了一些问题:

您不能指定要观看的包。使用该--pid=选项,您可以查看单个进程的输出。但是由于每次重新启动应用程序时 PID 都会发生变化,因此每次重新启动时都会重新运行此命令。

颜色很烦人(在我看来)。

输出字段与之前的消息不一致,整个内容的格式不正确,这使得跟踪 logcat 比它应该做的要困难得多(不过,嵌入式 logcat 也会发生同样的情况)。

所以我决定制作自己的工具来自动监视我的包 PID 并美化 logcat 输出:

import java.awt.AWTException;

import java.io.*;

import java.util.ArrayList;

import java.awt.Robot;

import java.awt.event.KeyEvent;

public class Logcat {

private static final String ADB_FILE_PATH = "adb";

// Customizations,

private static final Color V_COLOR = Color.RESET;

private static final Color D_COLOR = Color.RESET;

private static final Color I_COLOR = Color.RESET;

private static final Color W_COLOR = Color.BLUE;

private static final Color E_COLOR = Color.RED_BRIGHT;

private static final Color HINT_COLOR = Color.MAGENTA_BOLD_BRIGHT;

private static final Color OTHER_COLOR = Color.GREEN_BOLD_BRIGHT;

private static final int DATE_LENGTH = 5;

private static final int TIME_LENGTH = 12;

private static final int PROCESS_ID_LENGTH = 5;

private static final int THREAD_ID_LENGTH = 5;

private static final int LOG_LEVEL_LENGTH = 1;

private static final int TAG_LENGTH = 20;

private static final int MESSAGE_LENGTH = 110;

private static final String SEPARATOR = " | ";

private static final String CONTINUATION = "→";

private static final String INDENTATION = " ";

private static final int PROCESS_IDS_UPDATE_INTERVAL_MILLIS = 1224;

private static final int HISTORY_LENGTH = 1000;

// State,

private static boolean skipProcessIDCheck;

private static ArrayList processIDs = new ArrayList();

private static String logLevelToShow="V"; // All.

private static Process logcatProcess;

private static boolean appClosed;

private static boolean stopEverything;

private static String[] history = new String[HISTORY_LENGTH];

private static int currentLocationInHistory, historyLength;

public static void main(final String args[]) {

clearAndroidStudioConsole();

System.out.println("besm Allah");

// Get processes ids of the provided package,

if (args.length==0) {

skipProcessIDCheck = true;

} else {

skipProcessIDCheck = false;

getProcessIDs (args[0]); // Do it once before we start.

monitorProcessIDs(args[0]); // Do it periodically from now on.

}

// Start capturing and prettifying logcat,

if (!monitorLogcat()) {

stopEverything = true;

return;

}

// Handle user input,

handleUserInput();

}

private static void watch(final Process process, final ProcessListener listener) {

// Read process standard output and send it to the listener line by line,

new Thread() {

public void run() {

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

String line = "";

try {

do {

if (bufferedReader.ready()) {

line = bufferedReader.readLine();

if (line!=null && !line.isEmpty()) listener.onNewLine(line);

} else {

Thread.sleep(100);

}

} while (line!=null && !stopEverything);

} catch (Exception e) { e.printStackTrace(); }

}

}.start();

}

private static void monitorProcessIDs(String packageName) {

// Continuously monitor the process IDs of this package and update when changed,

new Thread() {

public void run() {

do {

try { Thread.sleep(PROCESS_IDS_UPDATE_INTERVAL_MILLIS); } catch (InterruptedException e) {}

getProcessIDs(packageName);

} while (!stopEverything);

}

}.start();

}

private static void getProcessIDs(String packageName) {

// Get the process IDs associated with this package once,

ArrayList newProcessIDs = new ArrayList();

Runtime runtime = Runtime.getRuntime();

try {

Process getPIDProcess = runtime.exec(ADB_FILE_PATH + " shell ps");

watch(getPIDProcess, (line) -> {

if (line.contains(packageName)) {

newProcessIDs.add(removeRedundantSpaces(line).split(" ")[1]);

}

});

getPIDProcess.waitFor();

Thread.sleep(500); // Make sure we've already handled all the input from the process.

} catch (Exception e) { e.printStackTrace(); }

// Return immediately if program is closed,

if (stopEverything) return ;

// Some action upon getting the pid(s),

boolean shouldRepeatHistory = false;

if (newProcessIDs.isEmpty()) {

// Just closed,

if (!appClosed) {

appClosed = true;

prettify("----- App closed -----");

}

} else if (appClosed) {

// Just opened, clear,

appClosed = false;

clearAndroidStudioConsole();

prettify("----- App opened -----");

shouldRepeatHistory = true;

} else {

// Detect changes in processes,

for (String pid : newProcessIDs) {

if (!processIDs.contains(pid)) {

clearAndroidStudioConsole();

prettify("----- Process(es) changed (or app restarted - some logs could have been missed) -----");

shouldRepeatHistory = true;

break ;

}

}

}

// Set the new PID(s),

processIDs = newProcessIDs;

if (shouldRepeatHistory) repeatHistory();

}

private static boolean monitorLogcat() {

Runtime runtime = Runtime.getRuntime();

try {

logcatProcess = runtime.exec(ADB_FILE_PATH + " logcat -v threadtime");

watch(logcatProcess, (line) -> {

// Learn history, in case we need to repeat it,

if (appClosed || processLogcatLine(line)) {

history[currentLocationInHistory] = line;

currentLocationInHistory = (currentLocationInHistory + 1) % history.length;

if (historyLength

}

});

} catch (Exception e) {

e.printStackTrace();

return false;

}

return true;

}

private static boolean processLogcatLine(String line) {

try {

return prettify(line);

} catch (Exception e) {

print(line, OTHER_COLOR);

System.out.println();

// Debug,

e.printStackTrace();

return true;

}

}

// Returns true if line should be kept in history,

private static synchronized boolean prettify(String line) {

if (line.startsWith("-")) {

// It's a "beginning of " line,

print(line, HINT_COLOR);

System.out.println();

return true;

}

// Get the individual fields,

String date = line.substring(0, line.indexOf(' ')); line = line.substring(line.indexOf(' ')+1); line = line.trim();

String time = line.substring(0, line.indexOf(' ')); line = line.substring(line.indexOf(' ')+1); line = line.trim();

String processID = line.substring(0, line.indexOf(' ')); line = line.substring(line.indexOf(' ')+1); line = line.trim();

// Break early if possible,

if (!skipProcessIDCheck && !processIDs.contains(processID.trim())) return false;

// Continue parsing,

String threadID = line.substring(0, line.indexOf(' ')); line = line.substring(line.indexOf(' ')+1); line = line.trim();

String logLevel = line.substring(0, line.indexOf(' ')); line = line.substring(line.indexOf(' ')+1); line = line.trim();

// Break early if possible,

switch (logLevel) {

case "V": if (!"V" .contains(logLevelToShow)) return true; break;

case "D": if (!"VD" .contains(logLevelToShow)) return true; break;

case "I": if (!"VDI" .contains(logLevelToShow)) return true; break;

case "W": if (!"VDIW" .contains(logLevelToShow)) return true; break;

case "E": if (!"VDIWE".contains(logLevelToShow)) return true; break;

}

// Continue parsing,

String tag = line.substring(0, line.indexOf(':')); line = line.substring(line.indexOf(':')+1); line = line.trim();

// Because some tags have a trailing ":",

if (line.startsWith(":")) {

tag += ":";

line = line.substring(1);

}

// Indent lines starting by "at",

String indentation = "";

if (line.startsWith("at ")) {

indentation = " " + INDENTATION;

line = " " + INDENTATION + line;

}

// Print the prettified log,

Color color;

switch (logLevel) {

case "V": color = V_COLOR; break;

case "D": color = D_COLOR; break;

case "I": color = I_COLOR; break;

case "W": color = W_COLOR; break;

case "E": color = E_COLOR; break;

default:

color = Color.RESET;

}

String fields = adjustLength( date, DATE_LENGTH) + SEPARATOR +

adjustLength( time, TIME_LENGTH) + SEPARATOR +

adjustLength(processID, PROCESS_ID_LENGTH) + SEPARATOR +

adjustLength( threadID, THREAD_ID_LENGTH) + SEPARATOR +

adjustLength( logLevel, LOG_LEVEL_LENGTH) + SEPARATOR +

adjustLength( tag, TAG_LENGTH) + SEPARATOR;

// Split the message onto multiple lines if needed,

String message = chunkPreservingParentheses(line, MESSAGE_LENGTH, 2);

print(fields + message, color);

System.out.println();

while (line.length() > message.length()) {

// Debug,

//print(line, OTHER_COLOR);

//System.out.println("Line: " + line.length() + "length: " + message.length() + ", cont: " + CONTINUATION.length() + "dent: " + indentation.length());

//System.out.println();

// Remove the already printed part.

line = line.substring(message.length()-CONTINUATION.length());

// Add a dot to make links work,

boolean shouldAddDot=false;

if (line.matches("^[^\\.]*\\(.*:[123456789][1234567890]*\\).*")) shouldAddDot = true;

// Indent,

line = (shouldAddDot ? "." : (indentation.isEmpty() ? "" : " ")) + indentation + line;

// Take another chunk,

message = chunkPreservingParentheses(line, MESSAGE_LENGTH, 2+indentation.length());

// Front pad to align this part with the message body,

String paddedMessage = message;

for (int i=0; i

// Print,

print(paddedMessage, color);

System.out.println();

}

return true; // Keep in local buffer.

}

private static String adjustLength(String text, int length) {

while (text.length() < length) text += ' ';

if (text.length() > length) {

text = text.substring(0, length-CONTINUATION.length());

text += CONTINUATION;

}

return text;

}

private static String chunkPreservingParentheses(String text, int length, int minChunckLength) {

if (text.length() <= length) return text;

// Take a chunk out of the text,

String chunk = text.substring(0, length-CONTINUATION.length()) + CONTINUATION;

// Check if a paranthesis was opened and not closed,

int lastOpenParanthesisIndex = chunk.lastIndexOf('(');

int lastCloseParanthesisIndex = chunk.lastIndexOf(')');

if (lastCloseParanthesisIndex <= lastOpenParanthesisIndex) { // Also works when either is not found.

if (minChunckLength<1) minChunckLength = 1;

if (lastOpenParanthesisIndex > minChunckLength+CONTINUATION.length()) { // Avoid endless loops.

int includeParenthesisSize = (CONTINUATION.length()>0) ? 1 : 0;

chunk = text.substring(0, lastOpenParanthesisIndex+includeParenthesisSize-CONTINUATION.length()) + CONTINUATION;

}

}

return chunk;

}

private static void repeatHistory() {

int index = currentLocationInHistory-historyLength;

if (index < 0) index += history.length;

for (int i=0; i

processLogcatLine(history[index]);

index = (index + 1) % history.length;

}

}

private static void print(String text, Color color) {

System.out.print(color);

System.out.print(text);

System.out.print(Color.RESET);

}

private static String removeRedundantSpaces(String text) {

String newText = text.replace(" ", " ");

while (!text.equals(newText)) {

text = newText;

newText = text.replace(" ", " ");

}

return text;

}

private static void clearAndroidStudioConsole() {

// Couldn't find a reliable way to clear Intellij terminal scrollback, so we just print

// a LOT of newlines,

StringBuilder bunchOfNewLines = new StringBuilder();

for (int i=0; i<124; i++) bunchOfNewLines.append(System.lineSeparator());

System.out.print(bunchOfNewLines);

// Scroll the current line to the top of the window,

try {

// If we are on Windows,

new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();

} catch (Exception e) {

// We are not on Windows,

bunchOfNewLines = new StringBuilder();

for (int i=0; i<124; i++) bunchOfNewLines.append("\b\r");

System.out.print(bunchOfNewLines);

}

}

private static void handleUserInput() {

// Line read. Unfortunately, java doesn't provide character by character reading out of the box.

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));

String input = "";

do {

try {

if (bufferedReader.ready()) {

input = input = bufferedReader.readLine().toUpperCase();

// Set log level,

if (input.equals("V")||input.equals("D")||input.equals("I")||input.equals("W")||input.equals("E")) {

if (!logLevelToShow.equals(input)) {

logLevelToShow = input;

clearAndroidStudioConsole();

repeatHistory();

}

prettify("----- Log level set to " + logLevelToShow + " -----");

} else if (input.equals("C")) {

// Clear screen and history,

clearAndroidStudioConsole();

historyLength = 0;

}

} else {

Thread.sleep(100);

}

} catch (Exception e) { e.printStackTrace(); }

// Check if the logcat process is still alive,

if (!logcatProcess.isAlive()) {

prettify("----- adb logcat process terminated -----");

stopEverything = true;

}

} while (!stopEverything && !input.equals("Q"));

// Allow all monitoring threads to exit,

stopEverything = true;

}

interface ProcessListener {

void onNewLine(String line);

}

enum Color {

// Thanks to this answer: https://stackoverflow.com/a/51944613/1942069

//Color end string, color reset

RESET("\033[0m"),

// Regular Colors. Normal color, no bold, background color etc.

BLACK ("\033[0;30m"),

RED ("\033[0;31m"),

GREEN ("\033[0;32m"),

YELLOW ("\033[0;33m"),

BLUE ("\033[0;34m"),

MAGENTA("\033[0;35m"),

CYAN ("\033[0;36m"),

WHITE ("\033[0;37m"),

// Bold

BLACK_BOLD ("\033[1;30m"),

RED_BOLD ("\033[1;31m"),

GREEN_BOLD ("\033[1;32m"),

YELLOW_BOLD ("\033[1;33m"),

BLUE_BOLD ("\033[1;34m"),

MAGENTA_BOLD("\033[1;35m"),

CYAN_BOLD ("\033[1;36m"),

WHITE_BOLD ("\033[1;37m"),

// Underline

BLACK_UNDERLINED ("\033[4;30m"),

RED_UNDERLINED ("\033[4;31m"),

GREEN_UNDERLINED ("\033[4;32m"),

YELLOW_UNDERLINED ("\033[4;33m"),

BLUE_UNDERLINED ("\033[4;34m"),

MAGENTA_UNDERLINED("\033[4;35m"),

CYAN_UNDERLINED ("\033[4;36m"),

WHITE_UNDERLINED ("\033[4;37m"),

// Background

BLACK_BACKGROUND ("\033[40m"),

RED_BACKGROUND ("\033[41m"),

GREEN_BACKGROUND ("\033[42m"),

YELLOW_BACKGROUND ("\033[43m"),

BLUE_BACKGROUND ("\033[44m"),

MAGENTA_BACKGROUND("\033[45m"),

CYAN_BACKGROUND ("\033[46m"),

WHITE_BACKGROUND ("\033[47m"),

// High Intensity

BLACK_BRIGHT ("\033[0;90m"),

RED_BRIGHT ("\033[0;91m"),

GREEN_BRIGHT ("\033[0;92m"),

YELLOW_BRIGHT ("\033[0;93m"),

BLUE_BRIGHT ("\033[0;94m"),

MAGENTA_BRIGHT("\033[0;95m"),

CYAN_BRIGHT ("\033[0;96m"),

WHITE_BRIGHT ("\033[0;97m"),

// Bold High Intensity

BLACK_BOLD_BRIGHT ("\033[1;90m"),

RED_BOLD_BRIGHT ("\033[1;91m"),

GREEN_BOLD_BRIGHT ("\033[1;92m"),

YELLOW_BOLD_BRIGHT ("\033[1;93m"),

BLUE_BOLD_BRIGHT ("\033[1;94m"),

MAGENTA_BOLD_BRIGHT("\033[1;95m"),

CYAN_BOLD_BRIGHT ("\033[1;96m"),

WHITE_BOLD_BRIGHT ("\033[1;97m"),

// High Intensity backgrounds

BLACK_BACKGROUND_BRIGHT ("\033[0;100m"),

RED_BACKGROUND_BRIGHT ("\033[0;101m"),

GREEN_BACKGROUND_BRIGHT ("\033[0;102m"),

YELLOW_BACKGROUND_BRIGHT ("\033[0;103m"),

BLUE_BACKGROUND_BRIGHT ("\033[0;104m"),

MAGENTA_BACKGROUND_BRIGHT("\033[0;105m"),

CYAN_BACKGROUND_BRIGHT ("\033[0;106m"),

WHITE_BACKGROUND_BRIGHT ("\033[0;107m");

private final String code;

Color(String code) { this.code = code; }

@Override public String toString() { return code; }

}

}

只需将此代码转储到Logcat.java并使用以下命令进行编译:

javac Logcat.java

并在 Android Studio 的嵌入式终端中运行:

java Logcat

例如:

java Logcat com.nomone.vr_desktop

结果如下所示:

它是高度可定制的,我在应用程序的第一部分中分离了大部分选项,因此您可以轻松调整颜色和格式。如果该adb工具不在您的 PATH 环境变量中,只需ADB_FILE_PATH在编译之前在变量中(在代码中)设置其完整路径。

当应用程序运行时,您可以键入以下快捷方式:

c清除屏幕和本地缓冲区。

v, i, d, w,e更改 logcat 级别。

q优雅地退出。Ctrl+c也可以。

不幸的是,您必须enter在按下这些键后按下。似乎Java不允许在不编写系统特定代码的情况下从控制台输入单个字符。对不起!

免责声明

如果使用 adb 连接了多个设备,这将不起作用。

我还没有彻底测试过这个。我只在一些设备上使用了一段时间。

我没有在 Windows 或 Mac 上测试过这个,但我尽量避免使用任何系统特定的东西,所以它应该仍然可以工作。

我希望这能解决你的问题:)

Copyright © 2088 世界杯乒乓球赛_2014世界杯十佳球 - mz286.com All Rights Reserved.
友情链接