寫在前面
這篇文章是我以前寫在CSDN上的辆床,由于感覺CSDN上寫作體驗(yàn)感覺不好佳晶,現(xiàn)在準(zhǔn)備把以前的一些文章轉(zhuǎn)到簡(jiǎn)書
以上都是廢話。讼载。宵晚。。维雇。
什么是IOC?
IOC框架稱為控制控制反轉(zhuǎn)框架也稱為依賴注入框架晒他,依賴注入(DI)和控制反轉(zhuǎn)(IOC)是從不同的角度的描述的同一件事情吱型,就是指通過引入IOC容器,利用依賴關(guān)系注入的方式陨仅,實(shí)現(xiàn)對(duì)象之間的解耦津滞。
IOC相關(guān)概念
在寫一個(gè)框架之前铝侵,我們需要了解下IOC的相關(guān)概念。
簡(jiǎn)單來說触徐,對(duì)象和IOC容器的關(guān)系就像電腦和外設(shè)之間的關(guān)系咪鲜,其中電腦相當(dāng)于對(duì)象,而IOC容器相當(dāng)于一個(gè)個(gè)不同的電腦外設(shè)撞鹉。外設(shè)具有不同的功能疟丙,并且他們和電腦之間都遵循著某種協(xié)議(如USB2.0協(xié)議),因此它們?cè)诒舜霜?dú)立的同時(shí)卻又能相互聯(lián)系鸟雏。
輸入功能原本屬于電腦的享郊,但是外設(shè)鍵盤卻能通過電腦提供的相關(guān)接口來控制電腦的輸入功能,這就是IOC概念里面的控制反轉(zhuǎn)孝鹊。由于電腦和外設(shè)間都遵循著USB協(xié)議炊琉,鍵盤便可以實(shí)現(xiàn)隨意切換,卻不影響鍵盤的輸入功能又活,這就是IOC概念里面的依賴注入苔咪。
好了,了解完IOC協(xié)議后柳骄,便可以開始繪制相應(yīng)的架構(gòu)圖了团赏。
IOC框架圖
這是我用StartUml繪制的UML圖。
如這個(gè)圖所示夹界,整個(gè)IOC框架可以分為5個(gè)部分
1馆里、ModuleListener,IOC的核心接口可柿,相當(dāng)于電腦的USB協(xié)議
2鸠踪、AbsModule,這就是IOC容器复斥,IOC容器功能都在這個(gè)類里面實(shí)現(xiàn)
3营密、IOCProxy,對(duì)象的靜態(tài)代理目锭,相當(dāng)于電腦的USB接口
4评汰、ModuleFactory,IOC容器的享元工廠痢虹,用于創(chuàng)建IOC容器
5被去、AbsActivity,具體的對(duì)象
有了概念奖唯,有了圖紙惨缆,現(xiàn)在終于可以愉快的碼代碼了
功能實(shí)現(xiàn)
ModuleListener
如上文所說的那樣,ModuleListener是整個(gè)IOC框架的IOC協(xié)議,它本質(zhì)上就是一個(gè)接口坯墨,定義了幾個(gè)方法寂汇,僅此而已,是的捣染,所謂的IOC協(xié)議就是那么簡(jiǎn)單骄瓣。
代碼如下:
public interface ModuleListener {
/**
* 無參的回調(diào)
*
* @param method 方法名
*/
public void callback(String method);
/**
* 帶參數(shù)的回調(diào)
*
* @param method 方法名
* @param dataClassType 參數(shù)類型
* @param data 數(shù)據(jù)
*/
public void callback(String method, Class<?> dataClassType, Object data);
/**
* 統(tǒng)一接口的回調(diào),回調(diào)接口為dataCallback
*
* @param result 返回碼
* @param data 回調(diào)數(shù)據(jù)
*/
public void callback(int result, Object data);
}
AbsModule
AbsModule耍攘,這就是IOC框架的IOC容器榕栏,IOC容器的功能都應(yīng)該在它的子類里面實(shí)現(xiàn)。
AbsModule依賴于ModuleListener接口少漆,它持有ModuleListener的引用臼膏。其實(shí)說白了它就是一個(gè)觀察者對(duì)象,僅此而已....
代碼如下:
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;
}
/**
* 統(tǒng)一的回調(diào)
*
* @param result 返回碼
* @param data 回調(diào)數(shù)據(jù)
*/
protected void callback(int result, Object data) {
mModuleListener.callback(result, data);
}
/**
* module回調(diào)
*
* @param method 回調(diào)的方法名
*/
@Deprecated
protected void callback(String method) {
mModuleListener.callback(method);
}
/**
* 帶參數(shù)的module回調(diào)
*
* @param method 回調(diào)的方法名
* @param dataClassType 回調(diào)數(shù)據(jù)類型
* @param data 回調(diào)數(shù)據(jù)
*/
@Deprecated
protected void callback(String method, Class<?> dataClassType, Object data) {
mModuleListener.callback(method, dataClassType, data);
}
}
IOCProxy
類如其名示损,IOCProxy本身就是一個(gè)靜態(tài)代理渗磅,代理本身其實(shí)很簡(jiǎn)單,說白了检访,代理就是我們平時(shí)所說的“黑中介”始鱼,在這里,我們的代理僅僅只實(shí)現(xiàn)了兩個(gè)功能:
1脆贵、給IOC對(duì)象設(shè)置觀察者医清,這個(gè)觀察者是繼承于AbsModule的子類。
2卖氨、中轉(zhuǎn)AbsModule回調(diào)的數(shù)據(jù)会烙,將數(shù)據(jù)再次回調(diào)到AbsActivity的相應(yīng)接口。
代碼如下:
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;
/**
* 初始化靜態(tài)代理
*/
public static IOCProxy newInstance(Object obj, AbsModule module) {
return new IOCProxy(obj, module);
}
/**
* 被代理對(duì)象
*/
private IOCProxy(Object obj, AbsModule module) {
this.mObj = obj;
if (module != null) {
module.setModuleListener(this);
}
}
/**
* 動(dòng)態(tài)切換不同的觀察者
* @param module
*/
public void changeModule(AbsModule module) {
module.setModuleListener(this);
}
/**
* 統(tǒng)一的數(shù)據(jù)回調(diào)
*
* @param result 返回碼
* @param data 回調(diào)數(shù)據(jù)
*/
@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();
}
}
}
/**
* 數(shù)據(jù)回調(diào)
*
* @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();
}
}
}
/**
* 帶參數(shù)的回調(diào)
*
* @param method 方法名
* @param dataClassType 參數(shù)類型,如 int.class
* @param data 數(shù)據(jù)
*/
@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();
}
}
}
}
在這個(gè)類里筒捺,博主根據(jù)以前的需求寫了幾種不同的代理回調(diào)柏腻。
但是,我強(qiáng)烈建議你使用帶有返回碼的統(tǒng)一回調(diào)接口系吭,該方法規(guī)定了AbsActivity的回調(diào)函數(shù)五嫂,實(shí)現(xiàn)了數(shù)據(jù)流的統(tǒng)一,一致性總歸是好的肯尺,便于我們后期維護(hù)沃缘。
ModuleFactory
ModuleFactory是一個(gè)享元工廠,IOC容器的構(gòu)建都是由它來完成了则吟,享元實(shí)現(xiàn)不同對(duì)象的容器之間的共享槐臀。
代碼如下:
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;
}
/**
* 構(gòu)造一個(gè)新的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框架的對(duì)象氓仲,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);
}
/**
* 利用反射來對(duì)代理進(jìn)行重指向
*/
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;
}
/**
* 統(tǒng)一的回調(diào)接口
*
* @param result 返回碼,用來判斷是哪個(gè)接口進(jìn)行回調(diào)
* @param data 回調(diào)數(shù)據(jù)
*/
protected abstract void dataCallback(int result, Object data);
}
總結(jié)
到現(xiàn)在為止讥巡,框架核心部分已經(jīng)完成了,現(xiàn)在讓我們整理下整個(gè)框架到底是怎樣運(yùn)作的舔哪!
老規(guī)矩欢顷,還是用圖來說明,沒什么比圖更讓人易懂的捉蚤。
下圖是整個(gè)框架的流程圖:
圖不難懂抬驴,我就不廢話了,我直接給出例子就行了缆巧,大家都是碼農(nóng)布持,我相信沒幾個(gè)碼農(nóng)喜歡看文字的,都喜歡看代碼直接干的陕悬。题暖。
例子
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的自定義回調(diào)......");
}
}
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);
}
/**
* 回調(diào)到自定義的方法
* @param data
*/
private void myCallback(String data){
show(data);
}
/**
* 數(shù)據(jù)回調(diào),當(dāng)然你也可以回調(diào)到指定的方法里面
* @param result 返回碼捉超,用來判斷是哪個(gè)接口進(jìn)行回調(diào)
* @param data 回調(diào)數(shù)據(jù)
*/
@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();
}
}