1. Introduction:

Android belongs to a small team development, the importance of architecture in many companies is not so obvious, and now open source frameworks emerge in an endless stream, better help us get started android project development. In the past two years, I also led project development in the company and built many projects. In the past, MY main tendency was MVC, which resulted in too large activity/fragment, and many public functions were mixed in the project, which made it inconvenient to maintain later. Recently, I just had time to rebuild a new framework. (PS: If you have suggestions or better ideas, please leave a comment.)

2.

UI—- object-oriented data interaction —-MVP schema database ——GreenDao network image loading —– Picasso json parsing port gson HTTP request HTTP eventbus —-eventbus


If you are not familiar with the above knowledge points, you can familiarize yourself with the basic knowledge first. If you have already known the basic knowledge, you can skip the following links and directly see the use of the following. The MVP pattern on address: blog.csdn.net/dfskhgalshg… GreenDao explain address: blog.csdn.net/dfskhgalshg… Picasso was explain address: blog.csdn.net/dfskhgalshg… OKHttp explain address: hon teach god’s blog address: blog.csdn.net/lmj62356579… Eventbus explain address: blog.csdn.net/dfskhgalshg…


3. Overall framework structure:

4. Project Directory structure:

Bean — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — – to store Java object model Biz — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — a business module, According to can’t business module son bridge — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — the underlying functions with the UI layer of cohesion “Capabilities — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — the underlying function concrete realization (late project iteration to a certain degree of stability will be considered in the form of a jar import) Constant — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — constant UI — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — the interface, According to the different business module son util — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — the business layer public methods View — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — the custom view

5

Or according to our habits of thinking, from the interface -> data —-> network —–> interaction, such a level of explanation.

1) the UI layer

UI layer is actually relatively simple, mainly using object-oriented encapsulation,BaseActivity as the base class,BaseActivity at the same time to achieve three interfaces, CreateInit, PublishActivityCallBack, and PresentationLayerFunc are used for interface initialization, page jump encapsulation, and page interaction encapsulation. PresentationLayerFunc concrete implementation is in PresentationLayerFuncHelper BaseActivity class will initialize the class, the realization of the function of the complex abstract out, lightweight base class.

The BaseActivity code looks like this:

/** * < basic activity> ** @author caoyinfei * @version @implements implements CreateInit public abstract BaseActivity extends Activity implements CreateInit, PublishActivityCallBack, PresentationLayerFunc, IMvpView, OnClickListener { private PresentationLayerFuncHelper presentationLayerFuncHelper; /** * return button */ private LinearLayout back; /** * protected TextView title, right; public BasePresenter presenter; public final String TAG = this.getClass().getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); presentationLayerFuncHelper = new PresentationLayerFuncHelper(this); initViews(); initListeners(); initData(); setHeader(); EBApplication.ebApplication.addActivity(this); EventBus.getDefault().register(this); } @Override public 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); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.ll_back: finish(); break; } } public void onEventMainThread(Event event) { } @Override protected void onResume() { EBApplication.ebApplication.currentActivityName = this.getClass().getName(); super.onResume(); } @Override public void startActivity(Class<? > openClass, Bundle bundle) { Intent intent = new Intent(this, openClass); if (null ! = bundle) intent.putExtras(bundle); startActivity(intent); } @Override public void openActivityForResult(Class<? > openClass, int requestCode, Bundle bundle) { Intent intent = new Intent(this, openClass); if (null ! = bundle) intent.putExtras(bundle); startActivityForResult(intent, requestCode); } @Override public void setResultOk(Bundle bundle) { Intent intent = new Intent(); if (bundle ! = null) ; intent.putExtras(bundle); setResult(RESULT_OK, intent); finish(); } @Override public void showToast(String msg) { presentationLayerFuncHelper.showToast(msg); } @Override public void showProgressDialog() { presentationLayerFuncHelper.showProgressDialog(); } @Override public void hideProgressDialog() { presentationLayerFuncHelper.hideProgressDialog(); } @Override public void showSoftKeyboard(View focusView) { presentationLayerFuncHelper.showSoftKeyboard(focusView); } @Override public void hideSoftKeyboard() { presentationLayerFuncHelper.hideSoftKeyboard(); } @Override protected 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(); }}Copy the code

PresentationLayerFuncHelper code as shown below:

** @author caoyinfei * @version 2016/6/6] * @ see [related class/method] * @ since (V1) * / public class PresentationLayerFuncHelper implements PresentationLayerFunc { private Context context; public PresentationLayerFuncHelper(Context context) { this.context = context; } @Override public void showToast(String msg) { ToastUtil.makeText(context, msg); } @Override public void showProgressDialog() { } @Override public void hideProgressDialog() { } @Override public void showSoftKeyboard(View focusView) { } @Override public void hideSoftKeyboard() { } }Copy the code

The CreateInit, PublishActivityCallBack, and PresentationLayerFunc interfaces are as follows:

/** * < public method abstract > ** @author caoyinfei * @version Public void initViews(); public void initViews(); /** * Add button click events */ void initListeners(); /** * Public void initData(); Public void setHeader(); public void setHeader(); }Copy the code
** @author caoyinfei * @version Public interface PublishActivityCallBack {/** * open a new interface ** @param openClass Public void startActivity(Class<? > openClass, Bundle bundle); /** * Open a new screen, Public void openActivityForResult(Class<? > openClass, int requestCode, Bundle bundle); ** @param bundle */ public void setResultOk(bundle); }Copy the code
** @author caoyinfei * @version 2016/6/6] @see [class/method] * @since [V1] */ public Interface PresentationLayerFunc {/** * @param MSG */ public void showToast(String msg); /** * public void showProgressDialog(); /** * public void hideProgressDialog(); /** * display softkeyboard ** @param focusView */ public void showSoftKeyboard(View focusView); /** * public void hideSoftKeyboard(); }Copy the code

For upper level development, the work is relatively simple, such as LoginActivity interface (LoginActivity), as long as the BaseActivity can be inherited, and then use IDE tools, automatically import the necessary override method. The code is as follows:

Public class LoginActivity extends BaseActivity implements IUserLoginView {/** * userName */ private EditText userName; /** * private EditText password; /** * private Button login; private LoginPresenter mUserLoginPresenter; @Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); super.onCreate(savedInstanceState); presenter = mUserLoginPresenter = new LoginPresenter(); mUserLoginPresenter.attachView(this); } @Override public void initViews() { userName = (EditText) findViewById(R.id.username); password = (EditText) findViewById(R.id.passowrd); login = (Button) findViewById(R.id.login); } @Override public void initListeners() { login.setOnClickListener(this); } @Override public void initData() { } @Override public void setHeader() { super.setHeader(); The title. The setText (" login "); } @Override public void onEventMainThread(Event event) { super.onEventMainThread(event); switch (event){ case IMAGE_LOADER_SUCCESS: clearEditContent(); break; } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.login: / / 13914786934 123456 can login mUserLoginPresenter. Login (userName. The getText (), toString (), the password. The getText (), toString ()); break; } super.onClick(v); } @Override public void clearEditContent() { userName.setText(""); password.setText(""); } @Override public void onError(String errorMsg, String code) { showToast(errorMsg); } @Override public void onSuccess() { startActivity(HomeActivity.class,null); } @Override public void showLoading() { } @Override public void hideLoading() { } }Copy the code

We should see that acitivty is full of interfaces, as long as the development of GG want to achieve the corresponding interface can be filled, the benefits of this implementation have several: 1. Each page is in this unified format, the late staff flow after easy maintenance. 2. Common processing, such as title bar, each page has, each page to separate implementation, code redundancy, this is removed to the BaseActivity inside the setHeader () method to unified processing, then each subclass can also customize special format, such as the title bar above the different titleName. 3. Public method abstraction to avoid repeating a lot of code for each activity.

2) In the data interaction layer, some people may see the MVP code in the above code, and will not understand it very well? Not so fast. Here’s how MVP works. Before, the activity layer did both interface and business logic, and the code volume was very large, often hundreds or thousands of lines. When the project was launched, the leader asked me to confuse it. I said at that time, we would not be able to understand this kind of code in a few months, do we still need to confuse it? Haha ~~ of course it’s a joke. Instead of MVC, an ACTIVITY does only two things: 1. Create a view. 2. User interaction. So where do we put the business logic? Here we introduce the Presenter layer, which is used to handle the business logic, and through IMvpView interface interaction with the activity (to explain in detail the MVP, the front have been very detailed introduction, address: blog.csdn.net/dfskhgalshg…

Presenter interacts with a View through an interface. So here we need to define an IUserLoginView, the difficulty lies in what methods should be, this is the login page, in fact, what functions, should have what methods, such as login success, failure, popup loading box these should notify the UI (Activity) to update. So the following methods are defined:

** @author caoyinfei * @version 2016/5/4] * @see [related class/method] * @since [V1] */ public interface IMvpView {void onError(String errorMsg, String code); void onSuccess(); void showLoading(); void hideLoading(); }Copy the code
** @author caoyinfei * @version 2016/5/4] * @see [class/method] * @since [product/module version] */ public interface IUserLoginView extends IMvpView {void clearEditContent(); }Copy the code

LoginPresenter is a business implementation class for logging in. It needs to do two things: 1. Business processing. 2. Refresh the notification page. The business process is very simple, so I won’t introduce it here. AttachView (V View) is a generic view. In this case, it is actually IUserLoginView. LoginActivity will implement this interface, at the time of initialization LoginPresenter, send it will transform itself mUserLoginPresenter. AttachView (this); —– is in the LoginActivity onCreate so that the Presenter notification page refresh is done through the interface.

/** * @author caoyinfei * @version @attachView (attachView); @attachView (attachView); @attachView (attachView); void detachView(V view); }Copy the code
/** * @author caoyinfei * @version 2016/6/6] * @implements implements public abstract class BasePresenter<V extends IMvpView> implements Presenter<V> { protected V mvpView; public void attachView(V view) { mvpView = view; } @Override public void detachView(V view) { mvpView = null; }}Copy the code
** @author caoyinfei * @version 2016/5/4] * @see [class/method] * @since [product/module version] */ public class extends BasePresenter<IUserLoginView> { Public LoginPresenter() {} public void login(String useName, String password) {// Network layer mvpView.showloading (); SecurityManager securityManager = BridgeFactory.getBridge(Bridges.SECURITY); OkHttpManager httpManager = BridgeFactory.getBridge(Bridges.HTTP); httpManager.requestAsyncPostByTag(URLUtil.USER_LOGIN, getName(), new ITRequestResult<LoginResp>() { @Override public void onCompleted() { mvpView.hideLoading(); } @Override public void onSuccessful(LoginResp entity) { mvpView.onSuccess(); EBSharedPrefManager manager = BridgeFactory.getBridge(Bridges.SHARED_PREFERENCE); manager.getKDPreferenceUserInfo().saveString(EBSharedPrefUser.USER_NAME, "abc"); } @Override public void onFailure(String errorMsg) { mvpView.onError(errorMsg, ""); } }, LoginResp.class, new Param("username", useName), new Param("pas", securityManager.get32MD5Str(password))); }}Copy the code
Public class LoginActivity extends BaseActivity implements IUserLoginView {/** * userName */ private EditText userName; /** * private EditText password; /** * private Button login; private LoginPresenter mUserLoginPresenter; @Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); super.onCreate(savedInstanceState); presenter = mUserLoginPresenter = new LoginPresenter(); mUserLoginPresenter.attachView(this); } @Override public void initViews() { userName = (EditText) findViewById(R.id.username); password = (EditText) findViewById(R.id.passowrd); login = (Button) findViewById(R.id.login); } @Override public void initListeners() { login.setOnClickListener(this); } @Override public void initData() { } @Override public void setHeader() { super.setHeader(); The title. The setText (" login "); } @Override public void onEventMainThread(Event event) { super.onEventMainThread(event); switch (event){ case IMAGE_LOADER_SUCCESS: clearEditContent(); break; } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.login: / / 13914786934 123456 can login mUserLoginPresenter. Login (userName. The getText (), toString (), the password. The getText (), toString ()); break; } super.onClick(v); } @Override public void clearEditContent() { userName.setText(""); password.setText(""); } @Override public void onError(String errorMsg, String code) { showToast(errorMsg); } @Override public void onSuccess() { startActivity(HomeActivity.class,null); } @Override public void showLoading() { } @Override public void hideLoading() { } }Copy the code

3) Network layer Network because Google no longer uses HttpClient after 6.0, the previous project through HttpClient to achieve network communication, now follow Google, changed to OKHttp framework. Are introduced, the interpretation of this framework is no longer simple, I posted a blog about address: hong god blog.csdn.net/lmj62356579… What I’ve done here is I’ve wrapped OKHttp in another layer to make it easier for us to use.

/**
 * <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;
        }

        @Override
        public void onFailure(Request request, IOException e) {
            EBLog.e(TAG, request.toString() + e.toString());
            if (!isHaveActivtyName(activityName)) return;
            notifyMsg = NETWORK_ERROR;
            postErrorMsg();
        }

        @Override
        public 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() {
                @Override
                public void run() {
                    mITRequestResult.onCompleted();
                    mITRequestResult.onFailure(notifyMsg);
                }
            });
        }

        /**
         * 主线程发送正确消息
         */
        private void postSucessMsg(final T res) {
            handler.post(new Runnable() {
                @Override
                public 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;
    }
}

Copy the code
** @author caoyinfei * @version */ public interface ITRequestResult<T> {public void onSuccessful(T entity); public void onFailure(String errorMsg); }Copy the code
/** * @author caoyinfei * @version Public class Param {public Param() {} public Param(String key, String key, 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; }Copy the code

1. Define the ITRequestResult interface to handle the Callback after the network request, and the Callback in this interface is in the main thread (the OKHttp Callback is in the child thread). 2.TRequestCallBack interface implementation. The network layer exception code is processed centrally and then returned to the UI layer. Centralized and unified processing of the normal situation of the network layer, through the JSON library, the network return is parsed into Java Model and returned to the UI layer. 3. Get, POST, cancel method encapsulation, convenient call.

4) Bridge layer abstraction

Duplicate code of each project much more special, a lot of projects like abstract public methods, but the project, a long period of time may be you don’t know, this method is defined, write in where, hard-working people global search again, some students may be the trouble, himself a new util class, write his own name, beginning to feel of eruption.

Here, we introduce BridgeFactory to unify the basic functions, similar to the implementation principle of local services. BridgeFactory implements file, network, database, security, and other management classes and stores references to them. When the business layer or the upper layer calls the underlying implementation, it is accessed through the BridgeFactory instead of directly.

** @author caoyinfei * @version 2016/6/6] * @see [related class/method] * @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; } / * * * initialize local storage path management class * / private void iniLocalFileStorageManager () {LocalFileStorageManager LocalFileStorageManager = new LocalFileStorageManager(); model.mBridges.put(Bridges.LOCAL_FILE_STORAGE, localFileStorageManager); BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(localFileStorageManager); 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); } /** * Initialize the security module */ private void initSecurityManager() {SecurityManager SecurityManager = new SecurityManager(); model.mBridges.put(Bridges.SECURITY, securityManager); BridgeLifeCycleSetKeeper.getInstance().trustBridgeLifeCycle(securityManager); } /** * Initializes user information module */ private void initUserSession() {} /** * Initializes Tcp service ** @param context */ private void InitCoreServiceManager (Context Context) {} private void initDBManager() {} /** * Through bridgeKey {@link Bridges} to get the corresponding Bridge module * * @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; }}Copy the code

In addition, through the BridgeLifeCycleListener interface, the unified initialization and destruction of all low-level function management classes can be realized to keep the life cycle consistent with the APP. The code is as follows:

/** * If the Bridge layer life cycle is related to the App life cycle (Application * onCreate initialization, user double click back exit), then implement this interface. Public interface BridgeLifeCycleListener {public void initOnApplicationCreate(Context Context); public void clearOnApplicationQuit(); }Copy the code

The Manager class code is as follows:

/**
 * <http公共解析库>
 *
 * @author caoyinfei
 * @version [版本号, 2016/6/6]
 * @see [相关类/方法]
 * @since [V1]
 */
public class OkHttpManager implements BridgeLifeCycleListener {

    @Override
    public 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);
    }

    @Override
    public void clearOnApplicationQuit() {
        OkHttpUtil.getInstance().destory();
    }
}

Copy the code

5) Multi-page interaction there may be multiple pages have logical relationships, such as HomeActivity after the successful loading of the image, the LoginActivity on the EditText content cleared, of course, I am a piece of garbage, but real development requirements are the same. I wipe, unintentionally reveal the love of product manager ~~~~. There might be people who use broadcasts, there might be people who use observers, there might be people who define static methods to call directly, but anyway, I’m not going to judge, because I’ve used it before… We change to EventBus to do the interaction between pages. I believe we all know the benefits of EventBus. EventBus is an android-optimized publish/subscribe EventBus. The main function is to replace Intent,Handler,BroadCast messages between fragments, activities, services, and threads. The advantages are lower overhead and more elegant code. And decouple the sender from the receiver.

The code used is as follows:

HomeActivity. Java classes

@Override public 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); // Send a refresh notification}Copy the code

LoginActivity. Java classes

@Override public void onEventMainThread(Event event) { super.onEventMainThread(event); Switch (event){// Accept notification case IMAGE_LOADER_SUCCESS: clearEditContent(); break; }}Copy the code
/** * < event type > ** @author caoyinfei * @version 2016/6/6] * @see [class/method] * @since [V1] */ public enum Event {/** * IMAGE_LOADER_SUCCESS,}Copy the code

6) Other public class encapsulation, of course, there are many classes of encapsulation, the framework is involved, here due to the time problem is not introduced, we can study by ourselves.

  • Encapsulation use of Gson
  • Log encapsulation, easy to go online, adjust the priority, close the Log
  • FileUtil Encapsulates common file operations
  • LocalFileStorageManager local file cache directory encapsulation
  • SecurityUtils encryption and decryption encapsulation (the previous article introduced the principle, the code should not appear in the encryption process, temporarily deleted)
  • GreenDao database encapsulation (GreenDao database encapsulation)

Blog.csdn.net/dfskhgalshg… .

6. Think about something else

1.Android dependency injection frameworks: Dagger, RoboGuice and ButterKnife. Dependency injection frameworks have different opinions. Some people highly recommend them, but I personally don’t like them. 2. This article is a single-project framework. The next article will introduce the componentized architecture

Project address: concern public number, message: Android project architecture source code can be obtained.


Please point out any mistakes and learn together.