kr.re.dev.LikeAA.LikeAA.java Source code

Java tutorial

Introduction

Here is the source code for kr.re.dev.LikeAA.LikeAA.java

Source

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();
    }

}