Ответ 1
Вы можете попробовать
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
String methodName = e.getMethodName();
Чтобы исправить тестовый случай, мне нужно определить, вызвана ли функция из конкретной функции вызывающего абонента. Я не могу позволить добавить логический параметр, потому что он нарушит определенные интерфейсы. Как это сделать?
Это то, чего я хочу достичь. Здесь я не могу изменить параметры операции(), поскольку это реализация интерфейса.
operation()
{
if not called from performancetest() method
do expensive bookkeeping operation
...
}
Вы можете попробовать
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
String methodName = e.getMethodName();
Вы можете найти метод вызова с помощью Stacktrace
Здесь функция, которую я написал для входа в функцию имени функции вызывающей ее функции. Он запускает трассировку стека, пока не найдет функцию с именем logIt, а затем отобразит следующее имя. Это грязный хак, поэтому не делайте этого, если вы не используете его для отладки.
private static void logIt() {
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
boolean logged = false;
boolean foundMe = false;
for(int i=0; i<stacktrace.length; i++) {
StackTraceElement e = stacktrace[i];
String methodName = e.getMethodName();
if (foundMe) {
if (!methodName.startsWith("access$")) {
Log.i(TAG, String.format(Locale.US, "%s.%s", e.getClassName(), methodName));
logged = true;
break;
}
} else {
if (methodName.equals("logIt")) {
foundMe = true;
}
}
}
if (!logged)
Log.e(TAG, "unlogged call");
}
Еще один пример использования Android:
//package your.package.name;
import android.util.Log;
/*
File name: MyDebugLog.java
*/
public class MyDebugLog {
private static final int index = 4; // <== Index in call stack array
private static final String methodName = "Log"; // <== Name of method for public call
private static String getCallerName() {
String caller = "NONE";
final StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
for (int i = 0; i < stacktrace.length; i++) {
Log.e("Method ", "[" + i + "]" + stacktrace[i].getMethodName());
}
if (stacktrace.length >= index){
caller = stacktrace[index].getMethodName();
}
return caller;
}
private static String getTag() {
String tag = "NONE";
final StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
for (int i = 0; i < stacktrace.length; i++) {
Log.e("Method ", "[" + i + "]" + stacktrace[i].getMethodName());
if (stacktrace[i].getMethodName().equals(methodName)) {
tag = "("+stacktrace[i + 1].getFileName() + ":" + stacktrace[i + 1].getLineNumber()+")";
return tag;
}
}
return tag;
}
public static void Log(String message){
Log.v(getTag(), getCallerName() + " " + message);
}
}
Использование:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_main);
MyDebugLog.Log("XXXXX");
}
Вывод:
V/(MainActivity.java:117): onCreate XXXXX
Пример массивов:
getTag Sample of stacktace array:
Method: [0]getThreadStackTrace
Method: [1]getStackTrace
Method: [2]getTag
Method: [3]Log <== Method for external call
...
getName Sample of stacktace array:
Method: [0]getThreadStackTrace
Method: [1]getStackTrace
Method: [2]getCallerName
Method: [3]Log
Method: [4]onCreate <== Our external method
Method: [5]performCreate
...
Я изменил код, который обсуждается здесь, и настроил его, чтобы получить метод вызова. Что здесь делает код, это перебрать элементы трассировки стека, и как только он найдет имя вызываемого метода, он получит имя предыдущего метода, который, в свою очередь, будет методом, вызывающим этот метод.
private String method() {
String methodName=null;
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
for (int i = 0; i < stacktrace.length; i++) {
if(stacktrace[i].getMethodName().equals("method")) {
methodName = stacktrace[i+1].getMethodName();
break;
}
}
return methodName;
}
Иногда я хочу сделать некоторые выводы для logcat. Итак, я написал крошечный класс с некоторыми методами тестирования:
public class Common {
// can be used as test-flag anywhere in the app (set to false, when release the app)
public static boolean b_TEST_MODE = true;
public static void echo(String message) {
if (b_TEST_MODE) {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
// subtring(25) is to cut off app-name from output
System.out.println(">>> " + stackTraceElements[3].toString().substring(25) + ": " + message);
}
}
}
теперь вы можете позвонить из любой точки приложения, чтобы получить информацию:
String sSQLQuery = "SELECT * FROM database WHERE id=23";
Common.echo(sSQLQuery);
Logcat распечатывает:
>>> MainActivity.onCreate(MainActivity.java:46): SELECT * FROM dateabase WHERE id=23
Я понятия не имею, почему, но в моем магазине разрабатываемая система отличается от тестовой и производственной сред, меняющих положение в стеке. Я был вынужден пройтись по стеку, чтобы найти и получить вызывающий метод из следующего элемента в трассировке стека. Немного грубее, но до сих пор последовательно возвращал желаемый метод. Я использую это как часть моей обработки ошибок, чтобы определить, где было обнаружено исключение.
List<String> list = new ArrayList<String>();
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
for (int i = 0; i < Thread.currentThread().getStackTrace().length; i++) {
System.out.println("Stack: "
+ i
+ " Class: "
+ elements[i].getClassName()
+ " Method: "
+ elements[i].getMethodName());
if (elements[i].getMethodName().equals("<init>")) {
list.add(elements[i + 1].getClassName());
list.add(elements[i + 1].getMethodName());
break;
} // if
} // for