Android项目架构搭建

1. 前言

安卓属于小团队开发,架构的重要性在很多公司其实不是那么的明显,加上现在的开源框架层出不穷,更好的帮助我们上手android项目的开发。我前两年也在公司主导过项目开发,搭建过不少项目,以前主要的倾向是MVC,导致了activity/fragment过大,而且很多公共功能杂乱在项目中,后期维护起来不方便,最近刚好有时间,重新搭建了一个新的框架。(ps:有建议或者更好想法的可以留言。)

2. 用到的知识点:

UI—-面向对象 
数据交互—-MVP模式 
数据库——GreenDao 
网络图片加载—–picasso 
json解析—–gson 
http请求—-OKHttp 
事件总线—-eventbus


以上知识点不熟悉的,可以先熟悉下基本知识,如果已经了解过,可以直接跳过下面的链接,直接看下文的使用。 
MVP模式 讲解地址:http://blog.csdn.net/dfskhgalshgkajghljgh/article/details/51317956 
GreenDao 讲解地址:http://blog.csdn.net/dfskhgalshgkajghljgh/article/details/51304390 
picasso 讲解地址:http://blog.csdn.net/dfskhgalshgkajghljgh/article/details/51684693 
OKHttp 讲解地址:鸿神的博客讲解地址: 
http://blog.csdn.net/lmj623565791/article/details/47911083 
eventbus 讲解地址:http://blog.csdn.net/dfskhgalshgkajghljgh/article/details/51681705


3. 框架整体结构:

4.项目目录结构:

bean—————————————————存放java model对象 
biz—————————————————–业务模块,根据不能业务建立子模块 
bridge————————————————-底层功能实现跟UI层的衔接层 
capabilities——————————————–底层功能具体实现(后期项目迭代到一定程度稳定后会考虑以jar形式导入) 
constant———————————————–常量 
ui——————————————————界面,根据不同业务建立子模块 
util—————————————————–业务层公共方法 
view—————————————————自定义view实现

5.具体解析

还是按照大家的习惯思维,从界面—>数据—->网络—–>交互,这样的层次讲解。

1)UI层

UI层其实比较简单,主要就是用到面向对象的封装,BaseActivity为基类,同时BaseActivity实现三个接口,分别为CreateInit, PublishActivityCallBack, PresentationLayerFunc,这三个接口的作用依次是:界面初始化,页面跳转封装,页面交互封装。PresentationLayerFunc的具体实现是在PresentationLayerFuncHelper里面,BaseActivity类会初始化该类,把复杂的功能实现抽象出去,轻量化基类。

BaseActivity代码如下所示:

/*** <基础activity>** @author caoyinfei* @version [版本号, 2014-3-24]* @see [相关类/方法]* @since [V1]*/
public abstract class BaseActivity extends Activity implements CreateInit, PublishActivityCallBack, PresentationLayerFunc, IMvpView, OnClickListener {private PresentationLayerFuncHelper presentationLayerFuncHelper;/*** 返回按钮*/private LinearLayout back;/*** 标题,右边字符*/protected TextView title, right;public BasePresenter presenter;public final String TAG = this.getClass().getSimpleName();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);presentationLayerFuncHelper = new PresentationLayerFuncHelper(this);initViews();initListeners();initData();setHeader();EBApplication.ebApplication.addActivity(this);EventBus.getDefault().register(this);}@Overridepublic void setHeader() {back = (LinearLayout) findViewById(R.id.ll_back);title = (TextView) findViewById(R.id.tv_title);right = (TextView) findViewById(R.id.tv_right);back.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.ll_back:finish();break;}}public void onEventMainThread(Event event) {}@Overrideprotected void onResume() {EBApplication.ebApplication.currentActivityName = this.getClass().getName();super.onResume();}@Overridepublic void startActivity(Class<?> openClass, Bundle bundle) {Intent intent = new Intent(this, openClass);if (null != bundle)intent.putExtras(bundle);startActivity(intent);}@Overridepublic void openActivityForResult(Class<?> openClass, int requestCode, Bundle bundle) {Intent intent = new Intent(this, openClass);if (null != bundle)intent.putExtras(bundle);startActivityForResult(intent, requestCode);}@Overridepublic void setResultOk(Bundle bundle) {Intent intent = new Intent();if (bundle != null) ;intent.putExtras(bundle);setResult(RESULT_OK, intent);finish();}@Overridepublic void showToast(String msg) {presentationLayerFuncHelper.showToast(msg);}@Overridepublic void showProgressDialog() {presentationLayerFuncHelper.showProgressDialog();}@Overridepublic void hideProgressDialog() {presentationLayerFuncHelper.hideProgressDialog();}@Overridepublic void showSoftKeyboard(View focusView) {presentationLayerFuncHelper.showSoftKeyboard(focusView);}@Overridepublic void hideSoftKeyboard() {presentationLayerFuncHelper.hideSoftKeyboard();}@Overrideprotected void onDestroy() {EBApplication.ebApplication.deleteActivity(this);EventBus.getDefault().unregister(this);if (presenter != null) {presenter.detachView(this);}OkHttpManager httpManager = BridgeFactory.getBridge(Bridges.HTTP);httpManager.cancelActivityRequest(TAG);super.onDestroy();}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129

PresentationLayerFuncHelper代码如下所示:

/*** <页面基础公共功能实现>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public class PresentationLayerFuncHelper implements PresentationLayerFunc {private Context context;public PresentationLayerFuncHelper(Context context) {this.context = context;}@Overridepublic void showToast(String msg) {ToastUtil.makeText(context, msg);}@Overridepublic void showProgressDialog() {}@Overridepublic void hideProgressDialog() {}@Overridepublic void showSoftKeyboard(View focusView) {}@Overridepublic void hideSoftKeyboard() {}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

三个接口,分别为CreateInit, PublishActivityCallBack, PresentationLayerFunc代码如下所示:


/*** <公共方法抽象>** @author caoyinfei* @version [版本号, 2014-3-24]* @see [相关类/方法]* @since [V1]*/
public interface CreateInit {/*** 初始化布局组件*/public void initViews();/*** 增加按钮点击事件*/void initListeners();/*** 初始化数据*/public void initData();/*** 初始化公共头部*/public void setHeader();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
/*** <页面跳转封装>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public interface PublishActivityCallBack {/*** 打开新界面** @param openClass 新开页面* @param bundle    参数*/public void startActivity(Class<?> openClass, Bundle bundle);/*** 打开新界面,期待返回** @param openClass 新界面* @param requestCode 请求码* @param bundle 参数*/public void openActivityForResult(Class<?> openClass, int requestCode, Bundle bundle);/*** 返回到上个页面** @param bundle 参数*/public void setResultOk(Bundle bundle);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
/*** <页面基础公共功能抽象>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public interface PresentationLayerFunc {/*** 弹出消息** @param msg*/public void showToast(String msg);/*** 网络请求加载框*/public void showProgressDialog();/*** 隐藏网络请求加载框*/public void hideProgressDialog();/*** 显示软键盘** @param focusView*/public void showSoftKeyboard(View focusView);/*** 隐藏软键盘*/public void hideSoftKeyboard();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

对于上层开发而言,工作就比较简单了,比如登录界面(LoginActivity),只要继承BaseActivity则可以了,然后用IDE工具,自动导入必要的override方法。 
代码如下:

public class LoginActivity extends BaseActivity implements IUserLoginView {/*** 用户名*/private EditText userName;/*** 用户密码*/private EditText password;/*** 登录*/private Button login;private LoginPresenter mUserLoginPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {setContentView(R.layout.activity_main);super.onCreate(savedInstanceState);presenter = mUserLoginPresenter = new LoginPresenter();mUserLoginPresenter.attachView(this);}@Overridepublic void initViews() {userName = (EditText) findViewById(R.id.username);password = (EditText) findViewById(R.id.passowrd);login = (Button) findViewById(R.id.login);}@Overridepublic void initListeners() {login.setOnClickListener(this);}@Overridepublic void initData() {}@Overridepublic void setHeader() {super.setHeader();title.setText("登录");}@Overridepublic void onEventMainThread(Event event) {super.onEventMainThread(event);switch (event){case IMAGE_LOADER_SUCCESS:clearEditContent();break;}}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.login://13914786934   123456  可以登录mUserLoginPresenter.login(userName.getText().toString(), password.getText().toString());break;}super.onClick(v);}@Overridepublic void clearEditContent() {userName.setText("");password.setText("");}@Overridepublic void onError(String errorMsg, String code) {showToast(errorMsg);}@Overridepublic void onSuccess() {startActivity(HomeActivity.class,null);}@Overridepublic void showLoading() {}@Overridepublic void hideLoading() {}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99

大家应该看得出,acitivty里面全是接口,开发gg只要把想应实现填到对应的接口中即可,这样实现的好处有几个: 
1.每个页面都是这种统一的格式,后期人员流动后维护方便。 
2.公共处理,比如title栏,每个页面都有,各个页面去单独实现,代码冗余,这边抽到BaseActivity 里面setHeader()方法去统一处理,当时各个子类也可以自定义特殊格式,比如title栏上面的titleName的不同。 
3.公共方法抽象,避免每个activity重复大量代码。

2)数据交互层 
可能有人会看到上面的代码中有MVP的代码,会看不太懂?别急,接下来讲解MVP的作用。 
之前activity层既做界面,又做业务逻辑,代码量特别大,动不动几百上千行,之前项目上线的时候,领导让我混淆一下,我当时说,这种代码,过几个月我们自己都看不懂了,还需要混淆吗?哈哈~~当然是开玩笑。 
言归正传,我们这边用MVP代替了MVC,从上面activity可以看出,activity只做两件事:1、view的创建。2、用户交互。那业务逻辑我们放在哪里呢?这里我们引入Presenter层,用来专门处理业务逻辑,并通过IMvpView接口实现跟activity的交互(mvp具体讲解,前面已经很详细的介绍过,地址:http://blog.csdn.net/dfskhgalshgkajghljgh/article/details/51317956)

代码如下: 
上面我们说过,Presenter与View交互是通过接口。所以我们这里需要定义一个IUserLoginView ,难点就在于应该有哪些方法,我们这个是登录页面,其实有哪些功能,就应该有哪些方法,比如登录成功,失败,弹出加载框这些都要通知ui(Activity)去更新。所以定义了如下方法:

/*** <功能详细描述>** @author caoyinfei* @version [版本号, 2016/5/4]* @see [相关类/方法]* @since [V1]*/
public interface IMvpView {void onError(String errorMsg, String code);void onSuccess();void showLoading();void hideLoading();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
/*** <功能详细描述>** @author caoyinfei* @version [版本号, 2016/5/4]* @see [相关类/方法]* @since [产品/模块版本]*/
public interface IUserLoginView extends IMvpView {void clearEditContent();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

LoginPresenter 为登录的业务实现类,他需要做两件事:1、业务处理。2.通知页面数据刷新。业务处理很简单,这边不做介绍了。Presenter与页面交互是通过接口实现的,这边通过继承基类BasePresenter,从而实现接口attachView(V view),这边的view是个泛型,在这里,他其实是IUserLoginView,LoginActivity会实现这个接口,在初始化LoginPresenter 的时候,会把自身传过来mUserLoginPresenter.attachView(this);—–这段代码是在LoginActivity的onCreate中,这样 Presenter通知页面刷新就只要通过接口就可以了。

/*** <基础业务类>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public interface Presenter<V> {void attachView(V view);void detachView(V view);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
/*** <基础业务类>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public abstract class BasePresenter<V extends IMvpView> implements Presenter<V> {protected V mvpView;public void attachView(V view) {mvpView = view;}@Overridepublic void detachView(V view) {mvpView = null;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
/*** <功能详细描述>** @author caoyinfei* @version [版本号, 2016/5/4]* @see [相关类/方法]* @since [产品/模块版本]*/
public class LoginPresenter extends BasePresenter<IUserLoginView> {public LoginPresenter() {}public void login(String useName, String password) {//网络层mvpView.showLoading();SecurityManager securityManager = BridgeFactory.getBridge(Bridges.SECURITY);OkHttpManager httpManager = BridgeFactory.getBridge(Bridges.HTTP);httpManager.requestAsyncPostByTag(URLUtil.USER_LOGIN, getName(), new ITRequestResult<LoginResp>() {@Overridepublic void onCompleted() {mvpView.hideLoading();}@Overridepublic void onSuccessful(LoginResp entity) {mvpView.onSuccess();EBSharedPrefManager manager = BridgeFactory.getBridge(Bridges.SHARED_PREFERENCE);manager.getKDPreferenceUserInfo().saveString(EBSharedPrefUser.USER_NAME, "abc");}@Overridepublic void onFailure(String errorMsg) {mvpView.onError(errorMsg, "");}}, LoginResp.class, new Param("username", useName),new Param("pas", securityManager.get32MD5Str(password)));}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
public class LoginActivity extends BaseActivity implements IUserLoginView {/*** 用户名*/private EditText userName;/*** 用户密码*/private EditText password;/*** 登录*/private Button login;private LoginPresenter mUserLoginPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {setContentView(R.layout.activity_main);super.onCreate(savedInstanceState);presenter = mUserLoginPresenter = new LoginPresenter();mUserLoginPresenter.attachView(this);}@Overridepublic void initViews() {userName = (EditText) findViewById(R.id.username);password = (EditText) findViewById(R.id.passowrd);login = (Button) findViewById(R.id.login);}@Overridepublic void initListeners() {login.setOnClickListener(this);}@Overridepublic void initData() {}@Overridepublic void setHeader() {super.setHeader();title.setText("登录");}@Overridepublic void onEventMainThread(Event event) {super.onEventMainThread(event);switch (event){case IMAGE_LOADER_SUCCESS:clearEditContent();break;}}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.login://13914786934   123456  可以登录mUserLoginPresenter.login(userName.getText().toString(), password.getText().toString());break;}super.onClick(v);}@Overridepublic void clearEditContent() {userName.setText("");password.setText("");}@Overridepublic void onError(String errorMsg, String code) {showToast(errorMsg);}@Overridepublic void onSuccess() {startActivity(HomeActivity.class,null);}@Overridepublic void showLoading() {}@Overridepublic void hideLoading() {}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

3)网络层 
网络由于google在6.0后不再使用httpclient,之前项目中通过httpclient实现了网络通信,现在跟随google,换成OKHttp框架。这个框架的讲解不再介绍了,比较简单,我贴一个鸿神的博客讲解地址: 
http://blog.csdn.net/lmj623565791/article/details/47911083有兴趣的可以去看看。 
我这边做的事情是,对OKHttp再做了一层封装,更方便我们使用。

/*** <http公共解析库>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public class OkHttpUtil {Handler handler = new Handler() {};private final String TAG = OkHttpUtil.class.getSimpleName();private static OkHttpUtil manager;private OkHttpClient mOkHttpClient;public final int TIMEOUT = 20;public final int WRITE_TIMEOUT = 20;public final int READ_TIMEOUT = 20;/*** 请求url集合*/private HashMap<String, Set<String>> requestMap;public OkHttpUtil() {requestMap = new HashMap<String, Set<String>>();mOkHttpClient = new OkHttpClient();mOkHttpClient.setConnectTimeout(TIMEOUT, TimeUnit.SECONDS);mOkHttpClient.setWriteTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);mOkHttpClient.setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS);}public static OkHttpUtil getInstance() {if (manager == null) {synchronized (OkHttpUtil.class) {if (manager == null) {return new OkHttpUtil();}}}return manager;}/*********************************************************** get请求*********************************************************//*** 异步Get请求 具体实现** @param url             请求url* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncGetEnqueue(String url, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {String constructUrl = constructUrl(url, params);Request request = new Request.Builder().get().url(constructUrl).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz));}/*** 异步Get请求 具体实现(可取消)** @param url             请求url* @param activityName    请求activityName* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncGetEnqueueByTag(String url, String activityName, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {addRequestUrl(activityName, url);String constructUrl = constructUrl(url, params);Request request = new Request.Builder().get().url(constructUrl).tag(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz, activityName));}/*** 构造get请求的url** @param url    不带参数的url* @param params 参数* @return 带参数的url*/private String constructUrl(String url, Param... params) {StringBuilder sb = new StringBuilder();sb.append(url);if (params.length != 0) {sb.append("?");} else {return sb.toString();}for (Param param :params) {sb.append(param.key + "=" + param.value + "&");}return sb.toString().substring(0, sb.length() - 1);}/*********************************************************** post请求*********************************************************//*** 异步POST请求  具体实现** @param url             请求url* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncPost(String url, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {FormEncodingBuilder builder = new FormEncodingBuilder();for (Param param :params) {builder.add(param.key, param.value);}RequestBody body = builder.build();Request request = new Request.Builder().post(body).url(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz));}/*** 异步POST请求  具体实现(可取消)** @param url             请求url* @param activityName    请求activityName* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncPostByTag(String url, String activityName, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {addRequestUrl(activityName, url);FormEncodingBuilder builder = new FormEncodingBuilder();for (Param param :params) {builder.add(param.key, param.value);}RequestBody body = builder.build();Request request = new Request.Builder().post(body).url(url).tag(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz, activityName));}/*** 异步DELETE请求  具体实现** @param url             请求url* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncDelete(String url, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {String finalUrl = constructUrl(url, params);Request request = new Request.Builder().delete().url(finalUrl).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz));}/*********************************************************** 文件请求*********************************************************//*** 异步POST请求 单文件上传** @param url             请求url* @param file            待上传的文件* @param key             待上传的key* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPost(String url, File file, String key, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);for (Param param :params) {builder.addFormDataPart(param.key, param.value);}builder = constructMultipartBuilder(builder, file, key);RequestBody body = builder.build();Request request = new Request.Builder().post(body).url(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz));}/*** 异步POST请求 单文件上传(可取消)** @param url             请求url* @param activityName    请求activityName* @param file            待上传的文件* @param key             待上传的key* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPostByTag(String url, String activityName, File file, String key, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {addRequestUrl(activityName, url);MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);for (Param param :params) {builder.addFormDataPart(param.key, param.value);}builder = constructMultipartBuilder(builder, file, key);RequestBody body = builder.build();Request request = new Request.Builder().post(body).url(url).tag(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz, activityName));}/*** 异步POST请求 多文件上传** @param url             请求url* @param files           待上传的文件s* @param keys            待上传文件的keys* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPost(String url, File[] files, String[] keys, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);for (Param param :params) {builder.addFormDataPart(param.key, param.value);}for (int i = 0; i < files.length; i++) {builder = constructMultipartBuilder(builder, files[i], keys[i]);}RequestBody body = builder.build();Request request = new Request.Builder().post(body).url(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz));}/*** 异步POST请求 多文件上传(可取消)** @param url             请求url* @param activityName    请求activityName* @param files           待上传的文件s* @param keys            待上传文件的keys* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPostByTag(String url, String activityName, File[] files, String[] keys, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {addRequestUrl(activityName, url);MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);for (Param param :params) {builder.addFormDataPart(param.key, param.value);}for (int i = 0; i < files.length; i++) {builder = constructMultipartBuilder(builder, files[i], keys[i]);}RequestBody body = builder.build();Request request = new Request.Builder().post(body).url(url).tag(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz, activityName));}/*** 异步POST请求 单图片上传上传** @param url             请求url* @param files           待上传图片数组* @param fileName        待上传图片名* @param key             待上传的key* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPost(String url, byte[] files, String fileName, String key, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);for (Param param :params) {builder.addFormDataPart(param.key, param.value);}RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), files);builder.addFormDataPart(key, fileName, requestBody);RequestBody body = builder.build();Request request = new Request.Builder().post(body).url(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz));}/*** 异步POST请求 单图片上传上传(可取消)** @param url             请求url* @param activityName    请求activityName* @param files           待上传图片数组* @param fileName        待上传图片名* @param key             待上传的key* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPostByTag(String url, String activityName, byte[] files, String fileName, String key, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {addRequestUrl(activityName, url);MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);for (Param param :params) {builder.addFormDataPart(param.key, param.value);}RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), files);builder.addFormDataPart(key, fileName, requestBody);RequestBody body = builder.build();Request request = new Request.Builder().post(body).url(url).tag(url).build();mOkHttpClient.newCall(request).enqueue(new TRequestCallBack(iTRequestResult, clazz, activityName));}/*** 构造多部件builer** @param builder 当前实例化MultipartBuilder* @param file    待上传文件* @param key     对应的参数名* @return 构造后的MultipartBuilder*/private MultipartBuilder constructMultipartBuilder(MultipartBuilder builder, File file, String key) {String name = file.getName();RequestBody requestBody = RequestBody.create(MediaType.parse(guessMimeType(name)), file);builder.addFormDataPart(key, name, requestBody);return builder;}/*** 获取文件类型** @param path* @return*/private String guessMimeType(String path) {FileNameMap fileNameMap = URLConnection.getFileNameMap();String contentTypeFor = fileNameMap.getContentTypeFor(path);if (contentTypeFor == null) {contentTypeFor = "application/octet-stream";}return contentTypeFor;}/*** 增加请求标志** @param activityName* @param url*/private void addRequestUrl(String activityName, String url) {if (requestMap.containsKey(activityName)) {requestMap.get(activityName).add(url);} else {Set<String> urlSet = new HashSet<String>();urlSet.add(url);requestMap.put(activityName, urlSet);}}/*** 取消正在请求的url** @param url 请求url*/public void cancelRequest(String url) {try {mOkHttpClient.getDispatcher().cancel(url);} catch (Exception ex) {ex.printStackTrace();}}/*** 取消当前页面正在的请求** @param activityName*/public void cancelActivityRequest(String activityName) {try {if (requestMap.containsKey(activityName)) {Set<String> urlSet = requestMap.get(activityName);for (String url : urlSet) {mOkHttpClient.getDispatcher().cancel(url);}requestMap.remove(activityName);}} catch (Exception ex) {ex.printStackTrace();}}/************************************************************** 回调方法*********************************************************/class TRequestCallBack<T> implements Callback {private ITRequestResult<T> mITRequestResult;private Class<T> clazz;private String notifyMsg = "";private String activityName;public TRequestCallBack(ITRequestResult<T> mITRequestResult, Class<T> clazz) {this.mITRequestResult = mITRequestResult;this.clazz = clazz;}public TRequestCallBack(ITRequestResult<T> mITRequestResult, Class<T> clazz, String activityName) {this.mITRequestResult = mITRequestResult;this.clazz = clazz;this.activityName = activityName;}@Overridepublic void onFailure(Request request, IOException e) {EBLog.e(TAG, request.toString() + e.toString());if (!isHaveActivtyName(activityName)) return;notifyMsg = NETWORK_ERROR;postErrorMsg();}@Overridepublic void onResponse(Response response) throws IOException {if (!isHaveActivtyName(activityName)) return;if (response.isSuccessful()) {String result = response.body().string(); //方法只能调用一次EBLog.i(TAG, result);final T res = GsonHelper.toType(result, clazz);int code = -1;if (res != null && res instanceof BaseResp) {code = ((BaseResp) res).getRetcode();switch (code) {case 000000:postSucessMsg(res);break;case 10005:case 10011://自动登录default:notifyMsg = ((BaseResp) res).getRetinfo();postErrorMsg();break;}} else {notifyMsg = SERVER_ERROR;postErrorMsg();}} else {notifyMsg = NETWORK_ERROR;postErrorMsg();}}/*** 主线程发送错误消息*/private void postErrorMsg() {handler.post(new Runnable() {@Overridepublic void run() {mITRequestResult.onCompleted();mITRequestResult.onFailure(notifyMsg);}});}/*** 主线程发送正确消息*/private void postSucessMsg(final T res) {handler.post(new Runnable() {@Overridepublic void run() {mITRequestResult.onCompleted();mITRequestResult.onSuccessful(res);}});}/*** 当前activity是否存在** @param activityName*/private boolean isHaveActivtyName(String activityName) {if (GeneralUtils.isNotNullOrZeroLenght(activityName)) {return requestMap.containsKey(activityName);} else {return true;}}}public static String SERVER_ERROR = "请求失败,请稍后再试";public static String NETWORK_ERROR = "您的网络状况不佳,请检查网络连接";public void destory() {manager = null;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
/*** <功能详细描述>** @author caoyinfei* @version [版本号, 2016/6/8]* @see [相关类/方法]* @since [产品/模块版本]*/
public interface ITRequestResult<T> {public void onSuccessful(T entity);public void onFailure(String errorMsg);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
/*** <参数类>** @author caoyinfei* @version [版本号, 2016/6/8]* @see [相关类/方法]* @since [V1]*/
public class Param {public Param() {}public Param(String key, String value) {this.key = key;this.value = value != null ? value : "";}public Param(String key, int value) {this.key = key;this.value = value + "";}String key;String value;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

应该已经很清楚了,我的做的事情有三个: 
1.定义ITRequestResult接口,用于处理网络请求后的回调,并且此接口中的回调在主线程中(OKHttp返回接口Callback是在子线程中 )。 
2.TRequestCallBack接口实现。 
集中统一处理网络层异常码然后返回到UI层。 
集中统一处理网络层正常情况,通过json库,把网络返回解析成java model返回给UI层。 
3.get,post,cancel方法封装,方便调用。

4)Bridge层抽象

每个项目中的重复代码特别多,很多项目喜欢抽象公共方法类,但是项目的时间一久,可能你自己都不清楚,这个方法是否定义过,写在哪里,勤快的人会全局搜一遍,有些同学可能会嫌麻烦,自己新建一个util类,写上自己的名字,顿时感觉自己萌萌的。

这边,我们引入了BridgeFactory,用来统一管理基础功能,类似本地服务的实现原理。 
BridgeFactory里面实现了文件,网络,数据库,安全等等管理类的实现,并保存了各类管理类的引用。业务层或者上层调用底层实现时,一律通过BridgeFactory去访问,而不是直接的调用。

/*** <中间连接层>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public class BridgeFactory {private static BridgeFactory model;private HashMap<String, Object> mBridges;private BridgeFactory() {mBridges = new HashMap<String, Object>();}public static void init(Context context) {model = new BridgeFactory();model.iniLocalFileStorageManager();model.initPreferenceManager();model.initSecurityManager();model.initUserSession();model.initCoreServiceManager(context);model.initOkHttpManager();}public static void destroy() {model.mBridges = null;model = null;}/*** 初始化本地存储路径管理类*/private void iniLocalFileStorageManager() {LocalFileStorageManager localFileStorageManager = new LocalFileStorageManager();model.mBridges.put(Bridges.LOCAL_FILE_STORAGE, localFileStorageManager);BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(localFileStorageManager);}/*** 初始化SharedPreference管理类*/private void initPreferenceManager() {EBSharedPrefManager ebSharedPrefManager = new EBSharedPrefManager();model.mBridges.put(Bridges.SHARED_PREFERENCE, ebSharedPrefManager);BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(ebSharedPrefManager);}/*** 网络请求管理类*/private void initOkHttpManager() {OkHttpManager mOkHttpManager = new OkHttpManager();model.mBridges.put(Bridges.HTTP, mOkHttpManager);BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(mOkHttpManager);}/*** 初始化安全模块*/private void initSecurityManager() {SecurityManager securityManager = new SecurityManager();model.mBridges.put(Bridges.SECURITY, securityManager);BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(securityManager);}/*** 初始化用户信息模块*/private void initUserSession() {}/*** 初始化Tcp服务** @param context*/private void initCoreServiceManager(Context context) {}private void initDBManager() {}/*** 通过bridgeKey {@link Bridges}来获取对应的Bridge模块** @param bridgeKey {@link Bridges}* @return*/@SuppressWarnings("unchecked")public static <V extends Object> V getBridge(String bridgeKey) {final Object bridge = model.mBridges.get(bridgeKey);if (bridge == null) {throw new NullPointerException("-no defined bridge-");}return (V) bridge;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103

并且,通过BridgeLifeCycleListener 接口,实现各个底层功能管理类的统一初始化跟销毁工作,保持跟app的生命周期一致。代码如下:

/*** 如果Bridge层的生命周期和App的生命周期相关(在Application* onCreate的时候初始化,在用户双击back键退出),则实现此接口,届时统一初始化和销毁*/
public interface BridgeLifeCycleListener {public void initOnApplicationCreate(Context context);public void clearOnApplicationQuit();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Manager类代码如下:

/*** <http公共解析库>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public class OkHttpManager implements BridgeLifeCycleListener {@Overridepublic void initOnApplicationCreate(Context context) {}/*** 异步Get请求 泛型返回** @param url             请求url* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncGet(String url, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncGetEnqueue(url, iTRequestResult, clazz, params);}/*** 异步Get请求 带tag(关闭页面则取消请求)** @param url             请求url* @param activityName    请求activityName* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncGetByTag(String url, String activityName, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncGetEnqueueByTag(url, activityName, iTRequestResult, clazz, params);}/*** 异步POST请求** @param url             请求url* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncPost(String url, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncPost(url, iTRequestResult, clazz, params);}/*** 异步POST请求 带tag(关闭页面则取消请求)** @param url             请求url* @param activityName    请求activityName* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncPostByTag(String url, String activityName, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncPostByTag(url, activityName, iTRequestResult, clazz, params);}/*** 异步DELETE请求** @param url             请求url* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数* @param <T>             泛型模板*/public <T> void requestAsyncDelete(String url, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncDelete(url, iTRequestResult, clazz, params);}/*** 异步POST请求 单文件上传** @param url             请求url* @param file            待上传的文件* @param key             待上传的key* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPost(String url, File file, String key, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncPost(url, file, key, iTRequestResult, clazz, params);}/*** 异步POST请求 单文件上传 带tag(关闭页面则取消请求)** @param url             请求url* @param activityName    请求activityName* @param file            待上传的文件* @param key             待上传的key* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPostByTag(String url, String activityName, File file, String key, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncPostByTag(url, activityName, file, key, iTRequestResult, clazz, params);}/*** 异步POST请求 多文件上传** @param url             请求url* @param files           待上传的文件s* @param keys            待上传文件的keys* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPost(String url, File[] files, String[] keys, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncPost(url, files, keys, iTRequestResult, clazz, params);}/*** 异步POST请求 多文件上传  带tag(关闭页面则取消请求)** @param url             请求url* @param activityName    请求activityName* @param files           待上传的文件s* @param keys            待上传文件的keys* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPostByTag(String url, String activityName, File[] files, String[] keys, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncPostByTag(url, activityName, files, keys, iTRequestResult, clazz, params);}/*** 异步POST请求 单图片上传上传** @param url             请求url* @param files           待上传图片数组* @param fileName        待上传图片名* @param key             待上传的key* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPost(String url, byte[] files, String fileName, String key, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncPost(url, files, fileName, key, iTRequestResult, clazz, params);}/*** 异步POST请求 单图片上传上传 带tag(关闭页面则取消请求)** @param url             请求url* @param activityName    请求activityName* @param files           待上传图片数组* @param fileName        待上传图片名* @param key             待上传的key* @param iTRequestResult 请求回调* @param clazz           Class<T>* @param params          请求参数*/public <T> void requestAsyncPostByTag(String url, String activityName, byte[] files, String fileName, String key, ITRequestResult<T> iTRequestResult, Class<T> clazz, Param... params) {OkHttpUtil.getInstance().requestAsyncPostByTag(url, activityName, files, fileName, key, iTRequestResult, clazz, params);}/*** 取消正在请求的url** @param url*/public void cancelRequest(String url) {OkHttpUtil.getInstance().cancelRequest(url);}/*** 取消当前页面正在请求的请求** @param activity*/public void cancelActivityRequest(String activity) {OkHttpUtil.getInstance().cancelActivityRequest(activity);}@Overridepublic void clearOnApplicationQuit() {OkHttpUtil.getInstance().destory();}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196

5)多页面交互 
可能会有多个页面存在逻辑关系,比如HomeActivity加载图片成功后,要通知LoginActivity上面的EditText内容清除,当然这个需求是我瞎扯的,然而真正开发中的需求何尝不是这样呢。我擦,无意间流露出对产品经理的喜爱~~~~。 
可能会有人用广播,用观察者,应该还有人会定义静态方法,去直接调用,不管怎么,我不评价,因为我之前也都用过。。。。 
我们这边改成eventbus去做页面之间的交互,eventbus的好处,相信大家都清楚。 
EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息.优点是开销小,代码更优雅。以及将发送者和接收者解耦。

使用的代码如下:

HomeActivity.java类

 @Overridepublic void initData() {Picasso.with(this).load("http://i.imgur.com/DvpvklR.png").resize(DensityUtil.dip2px(this,200), DensityUtil.dip2px(this,200)).centerCrop().into(image);EventBus.getDefault().post(Event.IMAGE_LOADER_SUCCESS);//发送刷新通知}
  • 1
  • 2
  • 3
  • 4
  • 5

LoginActivity.java类

 @Overridepublic void onEventMainThread(Event event) {super.onEventMainThread(event);switch (event){//接受通知case IMAGE_LOADER_SUCCESS:clearEditContent();break;}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
 /*** <事件类型>** @author caoyinfei* @version [版本号, 2016/6/6]* @see [相关类/方法]* @since [V1]*/
public enum Event {/*** 图片成功*/IMAGE_LOADER_SUCCESS,}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

6)其他公共类的封装 
当然还有很多类的封装,框架中都有涉及,这边由于时间问题不一一介绍了,大家可以自行研究。

  • Gson的封装使用
  • Log的封装,方便上线,调整优先级,关闭日志
  • FileUtil常用文件操作的封装
  • LocalFileStorageManager 本地文件缓存目录封装
  • SecurityUtils 加解密的封装(前面有文章介绍过原理,代码中不宜出现加密过程,暂时删除了)
  • 数据库封装 (前面有文章介绍过GreenDao,并有例子,这边不介绍了) 
    http://blog.csdn.net/dfskhgalshgkajghljgh/article/details/51304390 
    ……

6.其他思考

1.Android依赖注入的框架:Dagger、RoboGuice和ButterKnife,依赖注入的框架,见仁见智,有些人很推崇,但是我个人不怎么喜欢,首先影响了代码结构,代码交接成本高,个人小项目可以尝试使用,大的公司项目还是在考虑。 
2.rxjava先在个人项目中使用,熟练后再在框架中会引入。

由于框架暂时还没有在项目中试用一段时间,细节方面,好的或者不足的还希望大家勿喷,提出来我会持续改进。

项目地址: 
https://github.com/cyforever123/ElectronicbrandProject

Android 应用开发(1)---Android项目架构搭建相关推荐

  1. Android组件化打造知乎日报系列(一)—— 项目架构搭建

    Android组件化打造第三方知乎日报系列(一)-- 项目架构搭建 本节完整代码可以前往github查看,项目地址:github.com/N0tExpectEr- Android组件化打造知乎日报系列 ...

  2. 《Android App开发进阶与项目实战》资源下载和内容勘误

    资源下载 下面是<Android App开发进阶与项目实战>一书用到的工具和代码资源: 1.本书使用的Android Studio版本为4.2,最新的安装包可前往Android官网页面下载 ...

  3. 5G 时代的 Android App 开发入门与项目实战

    随着移动互联网的持续发展,Android系统从智能手机逐步拓展到平板电脑.智能电视.车载大屏.智能家居.智能手表等诸多设备,Android开发依然是前景可期的IT岗位. 当然,整个社会正在迈向5G时代 ...

  4. 《Android App开发进阶与项目实战》出版后记

    <Android App开发入门与项目实战>刚写完,我马上着手编写它的姊妹篇<Android App开发进阶与项目实战>,因为开发入门一书比较基础,还需要一本讲解高级开发与新技 ...

  5. 《Android App开发入门与项目实战》出版后记

    <Android Studio开发实战:从零基础到App上线>自面世以来,承蒙众多朋友的抬爱,该书一直保持不错的销量,其中第一版的出货量突破一万,第二版的出货量即将突破两万.对于一个程序员 ...

  6. 送书啦~《Android App开发进阶与项目实战》

    双十一刚结束,受我的编辑王老师所托,帮忙宣传<Android App开发进阶与项目实战>并赠送五本新书.该书介绍了很多新的技术,包括人工智能相关的. 1融合众多前沿技术 展现人工智能时代A ...

  7. android app开发混合开发,混合开发入门 Vue结合Android/iOS开发仿京东项目App

    download:混合开发入门 Vue结合Android/iOS开发仿京东项目App 无需原生开发基础,也能完美呈现京东商城.本课程融合vue.Android.IOS等目前流行的前端和移动端技术,混合 ...

  8. 【Android NDK 开发】Android Studio 使用 CMake 导入动态库 ( 构建脚本路径配置 | 指定动态库查找路径 | 链接动态库 )

    文章目录 I . CMake 引入动态库与静态库区别 II . Android Studio 中 CMake 引入动态库流程 III . 指定动态库查找路径 IV . 链接函数库 V . 完整代码示例 ...

  9. 【Android NDK 开发】Android Studio 使用 CMake 导入静态库 ( CMake 简介 | 构建脚本路径配置 | 引入静态库 | 指定静态库路径 | 链接动态库 )

    文章目录 I . CMake 简介 II . Android Studio 中 CMake 引入静态库流程 III . 指定 CMake 最小版本号 IV . 导入函数库 ( 静态库 / 动态库 ) ...

最新文章

  1. 读【36岁IT老人再次随笔】的读后感,你会哪些计算机语言?
  2. linux系统怎么安装python3视频教程_Linux系统,python3.7安装教程
  3. 《Java大学教程》—第23章 Java网络编程
  4. 从计算、建模到回测:因子挖掘的最佳实践
  5. 淘宝直播再升级!淘系自研GRTN 新一代多媒体传输网络
  6. js中英文字符与中文字符长度区别
  7. 计算机电源故障引起火灾,计算机硬件的常见故障及维护方法
  8. 关于NFC P2P模式
  9. 【Verilog基础】数字电路-逻辑式化简公式(附吸收律推导过程)
  10. Localhost到底是干什么用的?
  11. jupyter修改工作路径提示找不到指定模块
  12. Win10 微软拼音开启小鹤双拼的两种方法
  13. 等额本息、等额本金、等本等息概念
  14. 途虎养车产品经理面试(魔幻)
  15. php解决中文乱码,PHP中文乱码的常见解决方法总结
  16. android studio 中小米系列手机布局问题
  17. 金立(Gionee)金立M7 Power root 大金刚 GN5007 刷机TWRP 面具 XP框架 线刷包
  18. 项目经理需要的基本技能
  19. Cool Edit Pro 常用快捷键
  20. c语言中i++与++i的区别

热门文章

  1. 第二篇 模拟电子技术基础
  2. java的标识符可以以数字开头_标识符可以以数字开头,但不能是Java中的关键字...
  3. android 沉浸式状态栏 兼容低版本,详解Android沉浸式实现兼容解决办法
  4. c++已知2点求中垂线_电力系统负荷预测-基本方法以及分析(2)
  5. 《Reids 设计与实现》第十章 客户端
  6. JAVA多线程和并发基础面试题
  7. List、Map、Set之间的联系与区别:
  8. 【Gamma】 Phylab 发布说明
  9. 从Git的下载到使用github详细教程
  10. Redis常用数据类型和事物以及并发