Новые Thread
и решения AsyncTask уже объяснены.
AsyncTask
в идеале следует использовать для коротких операций. Обычный Thread
не является предпочтительным для Android.
Посмотрите альтернативное решение, используя HandlerThread и Обработчик
HandlerThread
Handy класс для запуска нового потока, который имеет петлитель. Затем петлитель можно использовать для создания классов обработчиков. Обратите внимание, что еще нужно вызвать
start()
.Обработчик:
Обработчик позволяет отправлять и обрабатывать объекты Message и Runnable, связанные с MessageQueue потока , Каждый экземпляр Handler связан с одним потоком и очередью сообщений этого потока. Когда вы создаете нового обработчика, он привязан к очереди потоков / сообщений потока, который его создает - с этой точки он будет доставлять сообщения и исполняемые файлы в очередь сообщений и выполнять их по мере их выхода из сообщения
Решение:
- Создать
HandlerThread
- Вызов
start()
наHandlerThread
- Создайте
Handler
, получивLooper
изHanlerThread
- Вставьте код связанного с вашей сетью объекта
Runnable
- Отправьте задание
Runnable
наHandler
Пример фрагмента кода, адрес
NetworkOnMainThreadException
HandlerThread handlerThread = new HandlerThread("URLConnection"); handlerThread.start(); handler mainHandler = new Handler(handlerThread.getLooper()); Runnable myRunnable = new Runnable() { @Override public void run() { try { Log.d("Ravi", "Before IO call"); URL page = new URL("http://www.google.com"); StringBuffer text = new StringBuffer(); HttpURLConnection conn = (HttpURLConnection) page.openConnection(); conn.connect(); InputStreamReader in = new InputStreamReader((InputStream) conn.getContent()); BufferedReader buff = new BufferedReader(in); String line; while ( (line = buff.readLine()) != null) { text.append(line + "\n"); } Log.d("Ravi", "After IO call"); Log.d("Ravi",text.toString()); }catch( Exception err){ err.printStackTrace(); } } }; mainHandler.post(myRunnable);
Плюсы использования этого подхода:
- Создание нового
Thread/AsyncTask
для каждая операция сети стоит дорого.Thread/AsyncTask
будет уничтожен и повторно создан для следующих сетевых операций. Но с подходамиHandler
иHandlerThread
вы можете отправить множество сетевых операций (как выполняемых задач) в одиночныйHandlerThread
с помощьюHandler
.
Для анализа байт-кода я бы рекомендовал ASM . Учитывая список классов для анализа, может быть сделан посетитель, который находит интересующие вас методы. Одна реализация, которая анализирует классы в файле jar, ниже.
Обратите внимание, что ASM использует internalNames с '/' вместо '.' как разделитель. Укажите целевой метод как стандартное объявление без модификаторов.
Например, чтобы перечислить методы, которые могли бы вызывать System.out.println ("foo") в java runtime jar :
java -cp "classes;asm-3.1.jar;asm-commons-3.1.jar" App \
c:/java/jdk/jre/lib/rt.jar \
java/io/PrintStream "void println(String)"
Редактировать : добавлены номера источников и строк: обратите внимание, что это указывает только на вызов последнего целевого метода для каждого метода вызова - оригинал q хотел узнать которые . Я оставляю это как упражнение для читателя, чтобы показать номера строк объявления вызывающего метода или номера строк каждого целевого вызова, в зависимости от того, что вы на самом деле после. :)
приводит к:
LogSupport.java:44 com/sun/activation/registries/LogSupport log (Ljava/lang/String;)V
LogSupport.java:50 com/sun/activation/registries/LogSupport log (Ljava/lang/String;Ljava/lang/Throwable;)V
...
Throwable.java:498 java/lang/Throwable printStackTraceAsCause (Ljava/io/PrintStream;[Ljava/lang/StackTraceElement;)V
--
885 methods invoke java/io/PrintStream println (Ljava/lang/String;)V
источник:
public class App {
private String targetClass;
private Method targetMethod;
private AppClassVisitor cv;
private ArrayList<Callee> callees = new ArrayList<Callee>();
private static class Callee {
String className;
String methodName;
String methodDesc;
String source;
int line;
public Callee(String cName, String mName, String mDesc, String src, int ln) {
className = cName; methodName = mName; methodDesc = mDesc; source = src; line = ln;
}
}
private class AppMethodVisitor extends MethodAdapter {
boolean callsTarget;
int line;
public AppMethodVisitor() { super(new EmptyVisitor()); }
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (owner.equals(targetClass)
&& name.equals(targetMethod.getName())
&& desc.equals(targetMethod.getDescriptor())) {
callsTarget = true;
}
}
public void visitCode() {
callsTarget = false;
}
public void visitLineNumber(int line, Label start) {
this.line = line;
}
public void visitEnd() {
if (callsTarget)
callees.add(new Callee(cv.className, cv.methodName, cv.methodDesc,
cv.source, line));
}
}
private class AppClassVisitor extends ClassAdapter {
private AppMethodVisitor mv = new AppMethodVisitor();
public String source;
public String className;
public String methodName;
public String methodDesc;
public AppClassVisitor() { super(new EmptyVisitor()); }
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
className = name;
}
public void visitSource(String source, String debug) {
this.source = source;
}
public MethodVisitor visitMethod(int access, String name,
String desc, String signature,
String[] exceptions) {
methodName = name;
methodDesc = desc;
return mv;
}
}
public void findCallingMethodsInJar(String jarPath, String targetClass,
String targetMethodDeclaration) throws Exception {
this.targetClass = targetClass;
this.targetMethod = Method.getMethod(targetMethodDeclaration);
this.cv = new AppClassVisitor();
JarFile jarFile = new JarFile(jarPath);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().endsWith(".class")) {
InputStream stream = new BufferedInputStream(jarFile.getInputStream(entry), 1024);
ClassReader reader = new ClassReader(stream);
reader.accept(cv, 0);
stream.close();
}
}
}
public static void main( String[] args ) {
try {
App app = new App();
app.findCallingMethodsInJar(args[0], args[1], args[2]);
for (Callee c : app.callees) {
System.out.println(c.source+":"+c.line+" "+c.className+" "+c.methodName+" "+c.methodDesc);
}
System.out.println("--\n"+app.callees.size()+" methods invoke "+
app.targetClass+" "+
app.targetMethod.getName()+" "+app.targetMethod.getDescriptor());
} catch(Exception x) {
x.printStackTrace();
}
}
}
Да, большинство современных IDE: s позволит вам либо искать способы использования метода или переменной. Кроме того, вы можете использовать отладчик и задавать точку трассировки в записи метода, печатать трассировку стека или все, что угодно при каждом вызове метода. Наконец, вы можете использовать некоторую простую оболочку для использования только метода grep для метода, такого как
find . -name '*.java' -exec grep -H methodName {} ;
. Единственный метод, который позволит вам находить вызовы, сделанные с помощью некоторого метода отражения, однако, будет использовать отладчик .
Самое близкое, что я мог найти, - это метод, описанный в этом ответе на выбранный вопрос StackOverflow. проверьте это
Вы можете сделать это с помощью чего-то в своей среде IDE, такой как «Найти использование» (это то, что вызывается в Netbeans и JDeveloper). Несколько замечаний:
Не существует способа сделать это (программно) через библиотеки отражения Java - вы не можете задать java.lang.reflect.Method "какие методы вы вызываете?"
Это оставляет два других варианта, о которых я могу думать:
В eclipse выделите имя метода, а затем Ctrl + Shift + G
Аннотировать метод с помощью @Deprecated (или пометить его с помощью @deprecated), включить предупреждения об устаревании, запустить компиляцию и посмотреть, какие предупреждения запускаются.
Запуск вашего компиляционного бита может быть сделан либо вызывая внешний процесс ant или с помощью API компилятора Java 6 .
1) В eclipse это -> щелкните правой кнопкой мыши на методе и выберите открытую иерархию вызовов или CLT+ALT+H
2) В jdeveloper это -> щелкните правой кнопкой мыши на методе и выберите вызовы или ALT+SHIFT+H
Я сделал небольшой пример, используя @ Chadwick's. Это тест, который оценивает, если вызовы getDatabaseEngine () создаются с помощью методов, которые реализуют @Transaction.
/**
* Ensures that methods that call {@link DatabaseProvider#getDatabaseEngine()}
* implement the {@link @Transaction} annotation.
*
* @throws Exception If something occurs while testing.
*/
@Test
public void ensure() throws Exception {
final Method method = Method.getMethod(
DatabaseEngine.class.getCanonicalName() + " getDatabaseEngine()");
final ArrayList<java.lang.reflect.Method> faultyMethods = Lists.newArrayList();
for (Path p : getAllClasses()) {
try (InputStream stream = new BufferedInputStream(Files.newInputStream(p))) {
ClassReader reader = new ClassReader(stream);
reader.accept(new ClassAdapter(new EmptyVisitor()) {
@Override
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
return new MethodAdapter(new EmptyVisitor()) {
@Override
public void visitMethodInsn(int opcode, String owner, String nameCode, String descCode) {
try {
final Class<?> klass = Class.forName(Type.getObjectType(owner).getClassName());
if (DatabaseProvider.class.isAssignableFrom(klass) &&
nameCode.equals(method.getName()) &&
descCode.equals(method.getDescriptor())) {
final java.lang.reflect.Method method = klass.getDeclaredMethod(name,
getParameters(desc).toArray(new Class[]{}));
for (Annotation annotation : method.getDeclaredAnnotations()) {
if (annotation.annotationType().equals(Transaction.class)) {
return;
}
}
faultyMethods.add(method);
}
} catch (Exception e) {
Throwables.propagate(e);
}
}
};
}
}, 0);
}
}
if (!faultyMethods.isEmpty()) {
fail("\n\nThe following methods must implement @Transaction because they're calling getDatabaseEngine().\n\n" + Joiner.on("\n").join
(faultyMethods) + "\n\n");
}
}
/**
* Gets all the classes from target.
*
* @return The list of classes.
* @throws IOException If something occurs while collecting those classes.
*/
private List<Path> getAllClasses() throws IOException {
final ImmutableList.Builder<Path> builder = new ImmutableList.Builder<>();
Files.walkFileTree(Paths.get("target", "classes"), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
if (file.getFileName().toString().endsWith(".class")) {
builder.add(file);
}
return FileVisitResult.CONTINUE;
}
});
return builder.build();
}
/**
* Gets the list of parameters given the description.
*
* @param desc The method description.
* @return The list of parameters.
* @throws Exception If something occurs getting the parameters.
*/
private List<Class<?>> getParameters(String desc) throws Exception {
ImmutableList.Builder<Class<?>> obj = new ImmutableList.Builder<>();
for (Type type : Type.getArgumentTypes(desc)) {
obj.add(ClassUtils.getClass(type.getClassName()));
}
return obj.build();
}
Изменить: исходный вопрос был отредактирован, чтобы указать, что требуется время исполнения - этот ответ был дан до этого редактирования и указывает только, как это сделать во время разработки.
Если вы используете Eclipse, вы можете править щелкните этот метод и выберите «Открыть иерархию вызовов», чтобы получить эту информацию.
Обновлено после чтения комментариев: Другие IDE также поддерживают это также (по крайней мере, Netbeans и IntelliJ do)
Появляется панель, в которой отображаются все ссылки на эти функции. Eclipse FTW!