Java tutorial
package kr.re.dev.LikeAA; import java.lang.annotation.Annotation; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import kr.re.dev.LikeAA.Annotations.AfterViews; import kr.re.dev.LikeAA.Annotations.Background; import kr.re.dev.LikeAA.Annotations.UiThread; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v4.app.Fragment; import android.view.View; /** * LikeAA <br/> * http://ice3x2.github.io/LikeAA/ <br/> * * LikeAA.java * <b>License </b><br/> * * Copyright (c) 2013 ice3x2@gmail.com Beom * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. <br/> * * v0.9.3 <br/> * : https://github.com/ice3x2/LikeAA/wiki/LikeAA * * @author ice3x2 * */ public class LikeAA { private BackgroundThreadRunner mBackgroundRunner; private UiThreadRunner mUiThreadRunner; private ViewFinder mFinder; private ListenerMapper mListenerMapper; private ArrayList<Method> mAfterViewsMethods = new ArrayList<Method>(); private static ExecutorService sExcutorMapping; private LikeAA() { } public static LikeAA map(Context context, Object target) { LikeAA likeAA = new LikeAA(); likeAA.mapping(likeAA.createFinder(context, target), target); return likeAA; } public static LikeAA map(View view, Object target) { LikeAA likeAA = new LikeAA(); likeAA.mapping(likeAA.createFinder(view, target), target); return likeAA; } public static LikeAA map(View targetView) { LikeAA likeAA = new LikeAA(); likeAA.mapping(likeAA.createFinder(targetView, targetView), targetView); return likeAA; } public static LikeAA map(Dialog targetDialog) { LikeAA likeAA = new LikeAA(); likeAA.mapping(likeAA.createFinder(targetDialog, targetDialog), targetDialog); return likeAA; } public static LikeAA map(Activity targetActivity) { LikeAA likeAA = new LikeAA(); likeAA.mapping(likeAA.createFinder(targetActivity, targetActivity), targetActivity); return likeAA; } public static LikeAA map(Fragment targetFragment) { LikeAA likeAA = new LikeAA(); likeAA.mapping(likeAA.createFinder(targetFragment, targetFragment), targetFragment); return likeAA; } private ArrayList<Method> getAfterViewMethods(Object target) { Method[] methods = target.getClass().getDeclaredMethods(); ArrayList<Method> afterViewMethodList = new ArrayList<Method>(); for (Method method : methods) { if (method.getAnnotation(AfterViews.class) != null) { afterViewMethodList.add(method); } } return afterViewMethodList; } private void mapping(ViewFinder finder, Object target) { mAfterViewsMethods.addAll(getAfterViewMethods(target)); mFinder = finder; initMapper(); if (mAfterViewsMethods.isEmpty()) mRunnableMapping.run(); else { initMappingExecutor(); sExcutorMapping.execute(mRunnableMapping); } } private Runnable mRunnableMapping = new Runnable() { @Override public void run() { mappinFieldByAnnotation(); callAfterViews(); mappingListenerByAnnotation(); } }; @SuppressLint("HandlerLeak") private void callAfterViews() { for (Method method : mAfterViewsMethods) { if (!method.isAccessible()) method.setAccessible(true); final WeakReference<Handler> waekHandler = new WeakReference<Handler>( new Handler(Looper.getMainLooper()) { public void dispatchMessage(Message msg) { Object target = mFinder.getTarget(); if (target == null) return; Method method = (Method) msg.obj; try { method.invoke(target, makeEmptyArgs(method.getParameterTypes())); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (Exception e) { Thread.getDefaultUncaughtExceptionHandler() .uncaughtException(Looper.getMainLooper().getThread(), e); } }; }); Message msg = waekHandler.get().obtainMessage(); msg.obj = method; waekHandler.get().sendMessage(msg); waekHandler.clear(); } } private ViewFinder createFinder(Object parent, Object target) { final WeakReference<Object> weakRefTarget = new WeakReference<Object>(target); if (parent == target) { return new ViewFinder(weakRefTarget); } else { final WeakReference<Object> weakRefParent = new WeakReference<Object>(parent); return new ViewFinder(weakRefParent, weakRefTarget); } } public boolean runBackground(Object... args) { return mBackgroundRunner.runBackground(args); } public boolean runUiThread(Object... args) { return mUiThreadRunner.runUiThread(args); } private void initMappingExecutor() { if (sExcutorMapping == null || sExcutorMapping.isShutdown()) { sExcutorMapping = Executors.newSingleThreadExecutor(); } } private void initMapper() { mBackgroundRunner = new BackgroundThreadRunner(mFinder); mUiThreadRunner = new UiThreadRunner(mFinder); mListenerMapper = new ListenerMapper(mFinder); } private void mappinFieldByAnnotation() { Object target = mFinder.getTarget(); // target ? ?? ? ? . if (target == null) return; FieldMapper mapper = new FieldMapper(mFinder); // TimeCheck long startTime = System.nanoTime(); mapper.callInjectionField(); long endTime = System.nanoTime(); System.out.println("callInjectionField() : " + ((endTime - startTime) / 1000.0f / 1000.0f) + "ms"); } private void mappingListenerByAnnotation() { Object target = mFinder.getTarget(); if (target == null) return; Method[] methods = target.getClass().getDeclaredMethods(); for (final Method method : methods) { Annotation[] annotations = method.getAnnotations(); // ?? ? Continue if (annotations == null || annotations.length == 0) continue; /*// ? ? . Class<?>[] params = method.getParameterTypes();*/ // annotation ? ? . for (Annotation annotation : annotations) { if (annotation instanceof Background) { // ? . //int delay = ((Background)annotation).value(); mBackgroundRunner.putRunnerMethod(method, 0); } else if (annotation instanceof UiThread) { // UI. int delay = ((UiThread) annotation).value(); mUiThreadRunner.putRunnerMethod(method, delay); } else { // . mListenerMapper.callInjectionListenerMethod(annotation, method); } } } mListenerMapper.recycle(); } @SuppressLint("UseValueOf") private Object[] makeEmptyArgs(Class<?>[] params) { Object[] args = new Object[params.length]; for (int i = 0, n = params.length; i < n; ++i) { if (params[i].isAssignableFrom(byte.class)) args[i] = new Byte((byte) 0); else if (params[i].isAssignableFrom(boolean.class)) args[i] = new Boolean(false); else if (params[i].isAssignableFrom(char.class)) args[i] = new Character((char) 0); else if (params[i].isAssignableFrom(int.class)) args[i] = new Integer(0); else if (params[i].isAssignableFrom(float.class)) args[i] = new Float(0.0f); else if (params[i].isAssignableFrom(long.class)) args[i] = new Long(0); else if (params[i].isAssignableFrom(double.class)) args[i] = new Double(0); else args[i] = null; } return args; } public void close() { mFinder.clear(); } }