繁体   English   中英

为什么“System.out.println”在Android 中不起作用?

[英]Why doesn't “System.out.println” work in Android?

我想在控制台中打印一些东西,以便我可以调试它。 但出于某种原因,我的 Android 应用程序中没有打印任何内容。

那我该如何调试呢?

public class HelloWebview extends Activity {
    WebView webview;    
    private static final String LOG_TAG = "WebViewDemo";
    private class HelloWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        webview = (WebView) findViewById(R.id.webview);
        webview.setWebViewClient(new HelloWebViewClient());
        webview.getSettings().setJavaScriptEnabled(true);
        webview.setWebChromeClient(new MyWebChromeClient());
        webview.loadUrl("http://example.com/");    
        System.out.println("I am here");
    }

更正:

在模拟器和大多数设备上System.out.println被重定向到 LogCat 并使用Log.i()打印。 这可能不适用于非常旧的或自定义的 Android 版本。

原来的:

没有控制台可以发送消息,因此System.out.println消息会丢失。 以同样的方式,当您使用javaw运行“传统”Java 应用程序时, javaw发生这种情况。

相反,您可以使用Android Log

Log.d("MyApp","I am here");

然后,您可以在 Eclipse 的Logcat视图中查看日志,或者运行以下命令:

adb logcat

养成查看 logcat 输出的习惯很好,因为这也是显示任何未捕获异常的堆栈跟踪的地方。

每个日志记录调用的第一个条目是标识日志消息来源的日志标记。 这很有用,因为您可以过滤日志的输出以仅显示您的消息。 为了确保您与您的日志标签一致,最好在某处将其定义为static final String

Log.d(MyActivity.LOG_TAG,"Application started");

Log一字法有五种,分别对应以下级别:

  • e() - 错误
  • w() - 警告
  • i() - 信息
  • d() - 调试
  • v() - 详细
  • wtf() - 多么可怕的失败

文档说明了以下级别

除非在开发过程中,否则不应将 Verbose 编译到应用程序中。 调试日志被编译但在运行时被剥离。 错误、警告和信息日志始终保留。

使用日志类 LogCat 输出可见

是的,它确实。 如果您使用模拟器,它将显示在System.out标记下的 Logcat 视图中。 写一些东西并在你的模拟器中尝试。

当然,要在logcat中看到结果,至少应该将Log级别设置为“Info”( logcat中的Log级别); 否则,就像我遇到的那样,您将看不到输出。

如果你真的需要 System.out.println 工作(例如,它是从第三方库调用的)。 您可以简单地使用反射来更改 System.class 中的字段:

try{
    Field outField = System.class.getDeclaredField("out");
    Field modifiersField = Field.class.getDeclaredField("accessFlags");
    modifiersField.setAccessible(true);
    modifiersField.set(outField, outField.getModifiers() & ~Modifier.FINAL);
    outField.setAccessible(true);
    outField.set(null, new PrintStream(new RedirectLogOutputStream()); 
}catch(NoSuchFieldException e){
    e.printStackTrace(); 
}catch(IllegalAccessException e){
    e.printStackTrace(); 
}

RedirectLogOutputStream 类:

public class RedirectLogOutputStream extends OutputStream{
    private String mCache;

    @Override
    public void write(int b) throws IOException{
        if(mCache == null) mCache = "";

        if(((char) b) == '\n'){
            Log.i("redirect from system.out", mCache);
            mCache = "";
        }else{
            mCache += (char) b;
        }
    }
}

它没有显示在您的应用程序中...它在您的模拟器的 logcat 下

手机上没有地方可以读取System.out.println();

相反,如果您想查看结果,请查看您的logcat/console窗口,或者在设备屏幕上显示ToastSnackbar (如果您使用的是较新的设备)并显示消息 :) 这就是我所做的例如,当我必须检查它在switch case代码中的位置时! 玩得开心编码! :)

System.out.println("...") 显示在 Android Studio 的 Android Monitor 上

我会把这个留给更多的访问者,因为对我来说这是关于主线程无法System.out.println事情。

public class LogUtil {

private static String log = "";
private static boolean started = false;
public static void print(String s) {
    //Start the thread unless it's already running
    if(!started) {
        start();
    }
    //Append a String to the log
    log += s;
}

public static void println(String s) {
    //Start the thread unless it's already running
    if(!started) {
        start();
    }
    //Append a String to the log with a newline.
    //NOTE: Change to print(s + "\n") if you don't want it to trim the last newline.
    log += (s.endsWith("\n") )? s : (s + "\n");
}

private static void start() {
    //Creates a new Thread responsible for showing the logs.
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            while(true) {
                //Execute 100 times per second to save CPU cycles.
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //If the log variable has any contents...
                if(!log.isEmpty()) {
                    //...print it and clear the log variable for new data.
                    System.out.print(log);
                    log = "";
                }
            }
        }
    });
    thread.start();
    started = true;
}
}

用法: LogUtil.println("This is a string");

我没有花哨的 IDE 来使用 LogCat,因为我使用的是移动 IDE。

我不得不使用各种其他方法,如果您需要,我有类和实用程序供您使用。

  1. 类 jav.android.Msg。 有一组静态方法。 A:打印android TOASTS的方法。 B:弹出对话框的方法。 每个方法都需要一个有效的上下文。 您可以设置默认上下文。

  2. 一个更雄心勃勃的方式,一个 Android 控制台。 您在应用程序中实例化控制台的句柄,它会启动控制台(如果已安装),并且您可以写入控制台。 我最近更新了控制台以实现从控制台读取输入。 在收到输入之前不会返回,就像常规控制台一样。 A:下载并安装 Android 控制台(从我这里获取) B:附带一个 java 文件(jav.android.console.IConsole)。 将其放在适当的目录中。 它包含操作 Android Console 的方法。 C:调用完成初始化的构造函数。 D:读取<*>并写入控制台。 还有工作要做。 即,由于 OnServiceConnected 不会立即调用,因此您不能在实例化它的同一函数中使用 IConsole。

  3. 在创建 Android Console 之前,我创建了 Console Dialog,这是一个在同一个应用程序中运行的对话框,类似于控制台。 优点:无需等待 OnServiceConnected 使用它。 缺点:当应用程序崩溃时,您不会收到导致应用程序崩溃的消息。

由于 Android Console 是单独进程中的单独应用程序,如果您的应用程序崩溃,您肯定会看到错误。 此外,IConsole 在您的应用程序中设置了一个未捕获的异常处理程序,以防您不热衷于异常处理。 它几乎将堆栈跟踪和异常消息打印到 Android 控制台。 最后,如果 Android 控制台崩溃,它会将其堆栈跟踪和异常发送给您,您可以选择一个应用程序来读取它。 实际上,AndroidConsole 不需要崩溃。

Edit Extras我注意到我的 while APK Builder 没有 LogCat; AIDE 可以。 然后我意识到无论如何都可以使用我的 Android 控制台。

  1. Android 控制台设计为仅占据屏幕的一部分,因此您可以看到您的应用程序以及从您的应用程序发送到控制台的数据。 这在 AIDE 中是不可能的。 所以我想触摸屏幕并查看坐标,Android Console 使这变得容易。

  2. Android 控制台旨在在您写入时弹出。

  3. 当您后退时,Android 控制台将隐藏。

最近我在 Android Studio 3.3 中发现了同样的问题。 我关闭了其他 Android Studio 项目,Logcat 开始工作。 上面接受的答案根本不合逻辑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM