在屏幕上显示日志的Android类库
16lz
2021-01-26
Galgo是Android日志类库,用于在屏幕上显示应用的日志信息。这对于测试人员和开发人员非常有用,可以根据屏幕上的日志文件了解应用出现BUG时发生的事情。
可以定义屏幕上显示日志的背景颜色、文本颜色、文本大小和日志显示的行数。
https://github.com/inaka/galgo
public class ExampleActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_example); // add some customization to the log messages GalgoOptions options = new GalgoOptions.Builder() .numberOfLines(15) .backgroundColor(Color.parseColor("#D9d6d6d6")) .textColor(Color.BLACK) .textSize(15) .build(); Galgo.enable(this, options); Galgo.log("I am a log message"); } public void onDestroy() { super.onDestroy(); // always call disable to avoid memory leaks Galgo.disable(this); }}
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.inaka.galgo"> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <application android:allowBackup="true" android:label="@string/app_name"> <service android:name=".GalgoService" /> </application></manifest>
改造了一下代码,
1.把Service做成一个全局的, 而不是bind到唯一的Activity , 这才是全局的Log
2.把GalgoOptions 放到了Galgo.java中
/* * Copyright (C) 2014 Inaka. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @author Henrique Boregio (henrique@inakanetworks.com) */package com.kookong.tv.debug;import android.content.Context;import android.content.Intent;import android.content.pm.PackageManager;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.os.Parcel;import android.os.Parcelable;import android.util.Log;import com.hzy.tvmao.TmApp;public class Galgo{ private static final Handler UI_HANDLER = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { if (!isServiceRunning) {//service 停止了就不要往service发消息了 return; } String message = (String) msg.obj; Intent intent = new Intent(TmApp.getContext(), GalgoService.class); intent.putExtra(MESSAGE, message); TmApp.getContext().startService(intent); } }; public static final String MESSAGE = "galgo.message"; public static final String ARG_OPTIONS = "galgo.options"; private static final String TAG = "Galgo"; private static GalgoOptions sOptions; private static Context sContext; private static boolean isServiceRunning; /** * * Starts a new Galgo with custom {@link com.inaka.galgo.GalgoOptions} * * @param context * Context * @param options * Custom {@link com.inaka.galgo.GalgoOptions} */ public static void enable(GalgoOptions options) { sOptions = options; init(); } /** * Starts a new Galgo with default {@link com.inaka.galgo.GalgoOptions} * * @param context * Context */ public static void enable() { enable(new GalgoOptions.Builder().build()); } private static void init() { sContext = TmApp.getContext(); checkPermission(sContext); // start a new service with our options Intent intent = new Intent(sContext, GalgoService.class); intent.putExtra(ARG_OPTIONS, sOptions); TmApp.getContext().startService(intent); isServiceRunning = true; } public static void disable() { Intent intent = new Intent(sContext, GalgoService.class); sContext.stopService(intent); sContext = null; isServiceRunning = false; } /** * Logs a String message to the screen. This String will be overlayed on top * of the UI elements currently displayed on screen. As a side effect, this * message will also be logged to the standard output via * {@link android.util.Log}. * * @param message * String to be displayed */ public static void log(String message) { Log.i(TAG, message); Message msg = UI_HANDLER.obtainMessage(0, message); msg.sendToTarget(); } private static void checkPermission(Context context) { String permission = "android.permission.SYSTEM_ALERT_WINDOW"; int status = context.checkCallingOrSelfPermission(permission); if (status == PackageManager.PERMISSION_DENIED) { throw new IllegalStateException("in order to use Galgo, " + "please add the permission " + permission + " to your AndroidManifest.xml"); } } public static final class GalgoOptions implements Parcelable { public final int numberOfLines; public final int backgroundColor; public final int textColor; public final int textSize; /** * Contains options for Galgo. Defines * * @param builder */ private GalgoOptions(Builder builder) { numberOfLines = builder.numberOfLines; backgroundColor = builder.backgroundColor; textColor = builder.textColor; textSize = builder.textSize; } /** * Builder for {@link com.inaka.galgo.GalgoOptions} */ public static class Builder { private int numberOfLines = 10; private int backgroundColor = 0xD993d2b9; private int textColor = 0xFFFFFFFF; private int textSize = 10; /** * * @param n * number of lines * @return */ public Builder numberOfLines(int n) { ensurePositiveInt(n, "number of lines must be > 0"); numberOfLines = n; return this; } /** * Sets the background color of the log messages * * @param color * @return */ public Builder backgroundColor(int color) { backgroundColor = color; return this; } /** * Sets the text color of the log messages * * @param color * @return */ public Builder textColor(int color) { textColor = color; return this; } /** * Sets the text size of the messages * * @param size * @return */ public Builder textSize(int size) { ensurePositiveInt(size, "text size must be > 0"); textSize = size; return this; } /** * Creates a {@link com.inaka.galgo.GalgoOptions} with the * customized parameters * * @return */ public GalgoOptions build() { return new GalgoOptions(this); } } private static void ensurePositiveInt(int value, String msg) { if (value <= 0) { throw new IllegalArgumentException(msg); } } // Parcelable implementation private GalgoOptions(Parcel source) { numberOfLines = source.readInt(); backgroundColor = source.readInt(); textColor = source.readInt(); textSize = source.readInt(); } public static final Creator<GalgoOptions> CREATOR = new Creator<GalgoOptions>() { @Override public GalgoOptions createFromParcel(Parcel source) { return new GalgoOptions(source); } @Override public GalgoOptions[] newArray(int size) { return new GalgoOptions[size]; } }; @Override public int describeContents() { return 0; // No special content. } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(numberOfLines); dest.writeInt(backgroundColor); dest.writeInt(textColor); dest.writeInt(textSize); } }}
/* * Copyright (C) 2014 Inaka. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @author Henrique Boregio (henrique@inakanetworks.com) */package com.kookong.tv.debug;import java.util.ArrayDeque;import java.util.Collection;import java.util.Queue;import android.app.Service;import android.content.Intent;import android.graphics.PixelFormat;import android.os.Binder;import android.os.IBinder;import android.text.Spannable;import android.text.SpannableString;import android.text.TextUtils;import android.text.style.BackgroundColorSpan;import android.view.Gravity;import android.view.WindowManager;import android.widget.TextView;import com.hzy.tvmao.utils.LogUtil;import com.hzy.tvmao.utils.SystemUtil;import com.kookong.tv.debug.Galgo.GalgoOptions;public class GalgoService extends Service{ private TextView mTextView; private GalgoOptions mOptions; private final Queue<String> mLines = new ArrayDeque<>(); @Override public int onStartCommand(Intent intent, int flags, int startId) { LogUtil.d("onStartCommand"); //首次创建有options GalgoOptions options = intent.getExtras().getParcelable(Galgo.ARG_OPTIONS); if (options != null) { mOptions = options; } //显示log的时候有Message String message = intent.getExtras().getString(Galgo.MESSAGE); if (!TextUtils.isEmpty(message)) { displayText(message); } return super.onStartCommand(intent, flags, startId); } @Override public void onCreate() { super.onCreate(); mTextView = new TextView(this); WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); wm.addView(mTextView, params); } public void displayText(String text) { mLines.add(text); if (mLines.size() > mOptions.numberOfLines) { mLines.poll(); } redraw(mLines); } private void redraw(Collection<String> texts) { mTextView.setTextSize(mOptions.textSize); mTextView.setTextColor(mOptions.textColor); mTextView.setPadding(SystemUtil.getScreenWH()[0] / 4, 0, 0, 0); Spannable spannable = new SpannableString(TextUtils.join("\n", texts)); spannable.setSpan(new BackgroundColorSpan(mOptions.backgroundColor), 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mTextView.setText(spannable); } @Override public void onDestroy() { super.onDestroy(); if (mTextView != null) { WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); wm.removeView(mTextView); } } @Override public IBinder onBind(Intent intent) { return null; }}
另一个开源项目, 显示所有日志
https://github.com/jgilfelt/GhostLog
更多相关文章
- Android之PreferenceActivity(配置界面详解)
- setContentView( )方法
- NDK DEBUG方法
- Android(安卓)java.lang.StackOverflowError at android.view.Vi
- android Toast 重复显示问题
- android常用控件一二
- TSwitch 中文简繁显示支持(XE6 Android)
- Android(安卓)沉浸式状态栏 最通俗易懂的总结
- 关于ScrollView嵌套RecyclerView时RecyclerView不显示的问题