打造属于你的Android IOC框架(一)

又是一个人的国庆,又是一个人闲的蛋疼,反正闲着也是闲着,打算在国庆期间把自己工作以来学到的知识整理一番。以纪念一个人闲的蛋疼的国庆!!


以上都是废话。。。。。

什么是IOC?

IOC框架称为控制控制反转框架也称为依赖注入框架,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

IOC相关概念

在写一个框架之前,我们需要了解下IOC的相关概念。
简单来说,对象和IOC容器的关系就像电脑和外设之间的关系,其中电脑相当于对象,而IOC容器相当于一个个不同的电脑外设。外设具有不同的功能,并且他们和电脑之间都遵循着某种协议(如USB2.0协议),因此它们在彼此独立的同时却又能相互联系。
输入功能原本属于电脑的,但是外设键盘却能通过电脑提供的相关接口来控制电脑的输入功能,这就是IOC概念里面的控制反转。由于电脑和外设间都遵循着USB协议,键盘便可以实现随意切换,却不影响键盘的输入功能,这就是IOC概念里面的依赖注入。

电脑和外设

好了,了解完IOC协议后,便可以开始绘制相应的架构图了。

IOC框架图

IOC框架图

这是我用StartUml绘制的UML图。

如这个图所示,整个IOC框架可以分为5个部分
1、ModuleListener,IOC的核心接口,相当于电脑的USB协议
2、AbsModule,这就是IOC容器,IOC容器功能都在这个类里面实现
3、IOCProxy,对象的静态代理,相当于电脑的USB接口
4、ModuleFactory,IOC容器的享元工厂,用于创建IOC容器
5、AbsActivity,具体的对象

有了概念,有了图纸,现在终于可以愉快的码代码了

功能实现

ModuleListener

如上文所说的那样,ModuleListener是整个IOC框架的IOC协议,它本质上就是一个接口,定义了几个方法,仅此而已,是的,所谓的IOC协议就是那么简单。
代码如下:

public interface ModuleListener {
    /**
     * 无参的回调
     *
     * @param method 方法名
     */
    public void callback(String method);

    /**
     * 带参数的回调
     *
     * @param method        方法名
     * @param dataClassType 参数类型
     * @param data          数据
     */
    public void callback(String method, Class<?> dataClassType, Object data);

    /**
     * 统一接口的回调,回调接口为dataCallback
     *
     * @param result        返回码
     * @param data          回调数据
     */
    public void callback(int result, Object data);
}

AbsModule

AbsModule,这就是IOC框架的IOC容器,IOC容器的功能都应该在它的子类里面实现。
AbsModule依赖于ModuleListener接口,它持有ModuleListener的引用。其实说白了它就是一个观察者对象,仅此而已….
代码如下:

public class AbsModule {
    public String TAG = "";
    private Context mContext;
    private ModuleListener mModuleListener;

    public AbsModule(Context context) {
        mContext = context;
        init();
    }

    /**
     * 初始化一些东西
     */
    private void init() {
        String className = getClass().getName();
        String arrays[] = className.split("\\.");
        TAG = arrays[arrays.length - 1];
    }

    public void setModuleListener(ModuleListener moduleListener) {
        if (moduleListener == null)
            throw new NullPointerException("ModuleListener为空");
        this.mModuleListener = moduleListener;
    }

    public Context getContext() {
        return mContext;
    }

    /**
     * 统一的回调
     *
     * @param result 返回码
     * @param data   回调数据
     */
    protected void callback(int result, Object data) {
        mModuleListener.callback(result, data);
    }

    /**
     * module回调
     *
     * @param method 回调的方法名
     */
    @Deprecated
    protected void callback(String method) {
        mModuleListener.callback(method);
    }

    /**
     * 带参数的module回调
     *
     * @param method        回调的方法名
     * @param dataClassType 回调数据类型
     * @param data          回调数据
     */
    @Deprecated
    protected void callback(String method, Class<?> dataClassType, Object data) {
        mModuleListener.callback(method, dataClassType, data);
    }
}

IOCProxy

类如其名,IOCProxy本身就是一个静态代理,代理本身其实很简单,说白了,代理就是我们平时所说的“黑中介”,在这里,我们的代理仅仅只实现了两个功能:
1、给IOC对象设置观察者,这个观察者是继承于AbsModule的子类。
2、中转AbsModule回调的数据,将数据再次回调到AbsActivity的相应接口。
代码如下:

import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class IOCProxy implements ModuleListener {
    private static final String TAG = "IOCProxy";
    private static final String mMethod = "dataCallback";

    private Object mObj;

    /**
     * 初始化静态代理
     */
    public static IOCProxy newInstance(Object obj, AbsModule module) {
        return new IOCProxy(obj, module);
    }

    /**
     * 被代理对象
     */
    private IOCProxy(Object obj, AbsModule module) {
        this.mObj = obj;
        if (module != null) {
            module.setModuleListener(this);
        }
    }

    /**
     * 动态切换不同的观察者
     * @param module
     */
    public void changeModule(AbsModule module) {
        module.setModuleListener(this);
    }

    /**
     * 统一的数据回调
     *
     * @param result 返回码
     * @param data   回调数据
     */
    @Override
    public void callback(int result, Object data) {
        synchronized (this) {
            try {
                Method m = mObj.getClass().getDeclaredMethod(mMethod, int.class, Object.class);
                m.setAccessible(true);
                m.invoke(mObj, result, data);
            } catch (NoSuchMethodException e) {
                Log.e(TAG, "无法找到" + mMethod + "方法");
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 数据回调
     *
     * @param method 方法名
     */
    @Override
    @Deprecated
    public void callback(String method) {
        synchronized (this) {
            try {
                Method m = mObj.getClass().getDeclaredMethod(method);
                m.setAccessible(true);
                m.invoke(mObj);
            } catch (NoSuchMethodException e) {
                Log.e(TAG, "无法找到" + method + "方法");
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 带参数的回调
     *
     * @param method        方法名
     * @param dataClassType 参数类型,如 int.class
     * @param data          数据
     */
    @Override
    @Deprecated
    public void callback(String method, Class<?> dataClassType, Object data) {
        synchronized (this) {
            try {
                Method m = mObj.getClass().getDeclaredMethod(method, dataClassType);
                m.setAccessible(true);
                m.invoke(mObj, data);
            } catch (NoSuchMethodException e) {
                Log.e(TAG, "无法找到" + method + "方法");
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个类里,博主根据以前的需求写了几种不同的代理回调。
但是,我强烈建议你使用带有返回码的统一回调接口,该方法规定了AbsActivity的回调函数,实现了数据流的统一,一致性总归是好的,便于我们后期维护。

ModuleFactory

ModuleFactory是一个享元工厂,IOC容器的构建都是由它来完成了,享元实现不同对象的容器之间的共享。
代码如下:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class ModuleFactory {

    private static final String TAG = "ModuleFactory";

    private static Map<String, AbsModule> mModules = new HashMap<>();

    /**
     * 获取Module
     */
    protected static <T extends AbsModule> T getModule(Context context, Class<T> clazz) {
        T module = (T) mModules.get(String.valueOf(clazz.hashCode()));
        if (module == null) {
            return newInstanceModule(context, clazz);
        }
        return module;
    }

    /**
     * 构造一个新的Module
     */
    private static <T extends AbsModule> T newInstanceModule(Context context, Class<T> clazz) {
        Class[] paramTypes = {Context.class};
        Object[] params = {context};
        try {
            Constructor<T> con = clazz.getConstructor(paramTypes);
            T module = con.newInstance(params);
            mModules.put(String.valueOf(clazz.hashCode()), module);
            return module;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}

AbsActivity

写了这么久,终于快到尾声了…
AbsActivity是IOC框架的对象,Activity也没啥好说的,大家都懂的,直接放代码:

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public abstract class AbsActivity extends AppCompatActivity {
    private static IOCProxy mProxy;
    private IOCProxy mNewProxy;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mNewProxy = IOCProxy.newInstance(this, null);
    }

    /**
     * 利用反射来对代理进行重指向
     */
    private void setProxy() {
        mProxy = mNewProxy;
    }

    /**
     * 获取Module
     */
    protected static <T extends AbsModule> T getModule(AbsActivity activity, Class<T> clazz) {
        Method m = ReflectionUtil.getMethod(activity.getClass(), "setProxy", new Class[]{});
        try {
            m.invoke(activity);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        T module = ModuleFactory.getModule(activity, clazz);
        mProxy.changeModule(module);
        return module;
    }

    /**
     * 统一的回调接口
     *
     * @param result 返回码,用来判断是哪个接口进行回调
     * @param data   回调数据
     */
    protected abstract void dataCallback(int result, Object data);
}

总结

到现在为止,框架核心部分已经完成了,现在让我们整理下整个框架到底是怎样运作的!
老规矩,还是用图来说明,没什么比图更让人易懂的。
下图是整个框架的流程图:
框架流程图
图不难懂,我就不废话了,我直接给出例子就行了,大家都是码农,我相信没几个码农喜欢看文字的,都喜欢看代码直接干的。。

例子

Module1

import android.content.Context;

import com.example.yuyu.blogframedemo.frame.AbsModule;

/**
 * Created by yuyu on 2015/9/6.
 */
public class Module1 extends AbsModule{
    public Module1(Context context) {
        super(context);
    }

    public void module1Test(){
        callback(100, "我是Module1111111");
    }

    public void cusomCallback(){
        callback("myCallback", String.class, "我是Module11的自定义回调......");
    }
}

Module2

import android.content.Context;

import com.example.yuyu.blogframedemo.frame.AbsModule;

/**
 * Created by yuyu on 2015/9/6.
 */
public class Module2 extends AbsModule{
    public Module2(Context context) {
        super(context);
    }

    public void module2Test(){
        callback(101, "我是Module22222222");
    }
}

MainActivity


import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.example.yuyu.blogframedemo.R;
import com.example.yuyu.blogframedemo.frame.AbsActivity;

/**
 * Created by yuyu on 2015/9/6.
 */
public class MainActivity extends AbsActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    /**
     * 回调到自定义的方法
     * @param data
     */
    private void myCallback(String data){
        show(data);
    }

    /**
     * 数据回调,当然你也可以回调到指定的方法里面
     * @param result 返回码,用来判断是哪个接口进行回调
     * @param data   回调数据
     */
    @Override
    protected void dataCallback(int result, Object data) {
        show(String.valueOf(data));
    }

    public void onClick(View view){
        switch (view.getId()){
            case R.id.module1:
                getModule(this, Module1.class).module1Test();
                break;
            case R.id.module2:
                getModule(this, Module2.class).module2Test();
                break;
            case R.id.custom_module:
                getModule(this, Module1.class).cusomCallback();
                break;
        }
    }

    private void show(String msg){
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
}

效果图


DEMO

猜你喜欢

转载自blog.csdn.net/qwe511455842/article/details/48845195