假设我们开发一个APP,版本一访问网络用的是HttpClient,版本二访问网络要求改成OKHttp,这种需求是不是很蛋疼,没关系,等我们学会了隔离层设计。这个问题就会迎刃而解。隔离层有三种实现方式:
1,代理模式 轻量级,耦合度高
2,HILT注入 重量级 耦合度低
3,SPI机制 零耦合 内存消耗大
我们一 一来看下。
代理模式
看下项目结构
看下httpprocessor代码
package com.example.test0530.httpprocessor;
import java.util.Map;
/**
* 房产公司
*/
public interface IHttpProcessor {
//有卖房的能力,访问网络的能力,这里只写一个POST请求,你可以添加其他请求方式
void post(String url, Map<String,Object> params,ICallback callback);
}
package com.example.test0530.httpprocessor;
/**
* 顶层的回调接口
*/
public interface ICallback {
void onSucess(String result);
void onFailure(String e);
}
package com.example.test0530.httpprocessor;
import java.util.Map;
public class HttpHelper implements IHttpProcessor{
//定义一个业主,卖房的人
private static IHttpProcessor mIHttpProcessor = null;
//通过API来设置哪一个业主卖出自己的房子,(谁来完成网络访问)
public static void init(IHttpProcessor httpProcessor){//传入第三方框架
mIHttpProcessor = httpProcessor;
}
//单例
private HttpHelper(){}
private static HttpHelper instance;
public static HttpHelper obtain(){
synchronized (HttpHelper.class){
if(instance == null){
instance = new HttpHelper();
}
}
return instance;
}
@Override
public void post(String url, Map<String, Object> params, ICallback callback) {
mIHttpProcessor.post(url, params, callback);
}
}
package com.example.test0530.httpprocessor;
import com.google.gson.Gson;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 回调接口的一种实现
*/
public abstract class HttpCallBack<T> implements ICallback {
@Override
public void onSucess(String result) {
//网络上回来的结果都在Result上,要做三件事
//1,得到调用者用什么样的javabean来接收数据
Class<?> clz = analysisClassInfo(this);//得到泛型result的类型
//2,把String 转成javabean
Gson gson = new Gson();
T objectResult = (T) gson.fromJson(result, clz);
//3,把结果交给用户(交给程序员使用)
sucess(objectResult);
}
//交给别人使用最好的就是用抽象方法
public abstract void sucess(T t);
@Override
public void onFailure(String e) {
}
/**
* 得到输入参数的实际类型
*/
private Class<?> analysisClassInfo(Object object) {
//获取到各种各样数据类型
Type type = object.getClass().getGenericSuperclass();
//获得各种泛型,比如我们传入了三个泛型,params数组就会有三个元素,三个class对象
Type[] params = ((ParameterizedType) type).getActualTypeArguments();
//我只有一个泛型,所以返回数组的第0个元素
return (Class<?>) params[0];
}
}
各类网络访问框架,有需要自己可以加更多。这里只展示两种。
package com.example.test0530.volley;
import android.content.Context;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.example.test0530.httpprocessor.ICallback;
import com.example.test0530.httpprocessor.IHttpProcessor;
import java.util.Map;
public class VolleyProcessor implements IHttpProcessor {
//以下是volley的用法
private static RequestQueue mQueue = null;
public VolleyProcessor(Context context) {
mQueue = Volley.newRequestQueue(context);
}
@Override
public void post(String url, Map<String, Object> params, ICallback callback) {
// //获取第三方框架从网络回来的String结果
// callback.onSucess();
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
//这句代码至为关键
callback.onSucess(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
mQueue.add(stringRequest);
}
}
package com.example.test0530.okhttp;
import com.example.test0530.httpprocessor.ICallback;
import com.example.test0530.httpprocessor.IHttpProcessor;
import java.util.Map;
public class OKHttpProcessor implements IHttpProcessor {
@Override
public void post(String url, Map<String, Object> params, ICallback callback) {
略
}
}
接下来我们看下怎么使用
package com.example.test0530;
import com.example.test0530.httpprocessor.HttpHelper;
import com.example.test0530.okhttp.OKHttpProcessor;
import com.example.test0530.volley.VolleyProcessor;
public class Application extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
//以前我们用Volley,后来要改成OKHTTP,我们在这里该一句代码就可以了。
//但是单例初始化后,对象就不会释放,耦合度很高。
// HttpHelper.init(new VolleyProcessor(this));
HttpHelper.init(new OKHttpProcessor());
}
}
package com.example.test0530
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.test0530.httpprocessor.HttpCallBack
import com.example.test0530.httpprocessor.HttpHelper
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val url = ""
val parames = null;
HttpHelper.obtain().post(url,parames,object: HttpCallBack<JavaBean>() {
override fun sucess(t: JavaBean?) {
TODO("Not yet implemented")
}
})
}
}
package com.example.test0530;
public class JavaBean {
}
不过这种方法已经过时了,18年以前可以这么干。现在就有点out了。现在我们用第二种方式来实现。
HILT注入
专门针对Android的依赖注入框架,由Dagger2团队提供,我们看下如何使用
先看下依赖的添加
项目gradle中
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
//新增
id 'dagger.hilt.android.plugin'
id 'kotlin-kapt'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.example.test0530"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//新增
implementation "com.google.dagger:hilt-android:2.41"
kapt "com.google.dagger:hilt-android-compiler:2.41"
//新增net
implementation("com.android.volley:volley:1.2.1")
implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation("org.xutils:xutils:3.4.0")
implementation 'com.google.code.gson:gson:2.9.0'
}
根gradle中
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.2.1' apply false
id 'com.android.library' version '7.2.1' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
//新增
id 'com.google.dagger.hilt.android' version '2.41' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}
我们现在用注解生成一个HttpObject对象
package com.example.test0530;
public class HttpObject {
//网络访问对象,项目用什么由你自己决定
}
package com.example.test0530;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.android.components.ActivityComponent;
import dagger.hilt.android.scopes.ActivityScoped;
@InstallIn(ActivityComponent.class)//在哪个组件使用
@Module
public class HttpModele {
// @Singleton //全局单例模式
//@ActivityScoped//只在一个Activity里面单例模式
@Provides
public HttpObject getHttpObject(){
//对象初始化......
return new HttpObject();
}
}
Application的配置
package com.example.test0530;
import dagger.hilt.android.HiltAndroidApp;
@HiltAndroidApp//这个注解必须在APPlication添加
public class MyApplication extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
}
}
package com.example.test0530;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
HttpObject httpObject;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//这里就可以使用httpObject对象了
}
}
除此之外,hilt还支持接口注入
package com.example.test0530;
public interface TestInterface {
void method();
}
package com.example.test0530;
import javax.inject.Inject;
public class TestClass implements TestInterface{
//一定要写构造方法
@Inject
public TestClass(){}
@Override
public void method() {
System.out.println("----------------");
}
}
package com.example.test0530;
import dagger.Binds;
import dagger.Module;
import dagger.hilt.InstallIn;
import dagger.hilt.android.components.ActivityComponent;
@InstallIn(ActivityComponent.class)
@Module
public abstract class TestInterfaceModule {
@Binds//绑定接口实现来
public abstract TestInterface abc(TestClass testClass);
// 返回接口,参数为实现类
}
Application同上
下面我们看下怎么使用Hilt来做隔离层设计
package com.example.test0530;
import javax.inject.Inject;
import dagger.hilt.android.HiltAndroidApp;
@HiltAndroidApp//这个注解必须在APPlication添加
public class MyApplication extends android.app.Application {
@BindVOlley
@Inject
IHttpProcessor iHttpProcessor;
@Override
public void onCreate() {
super.onCreate();
}
public IHttpProcessor getiHttpProcessor() {
return iHttpProcessor;
}
}
package com.example.test0530;
import java.util.Map;
import javax.inject.Inject;
public class OKHttpProcessor implements IHttpProcessor{
@Inject
public OKHttpProcessor() {
}
@Override
public void post(String url, Map<String, Object> params, ICallback callback) {
}
}
package com.example.test0530;
import android.content.Context;
import java.util.Map;
import javax.inject.Inject;
import dagger.hilt.android.qualifiers.ApplicationContext;
public class VolleyProcessor implements IHttpProcessor{
@Inject
public VolleyProcessor(@ApplicationContext Context context) {
//注入上下文
}
@Override
public void post(String url, Map<String, Object> params, ICallback callback) {
}
}
package com.example.test0530;
import javax.inject.Singleton;
import dagger.Binds;
import dagger.Module;
import dagger.hilt.InstallIn;
import dagger.hilt.components.SingletonComponent;
@Module
@InstallIn(SingletonComponent.class)//相当于旧版本的ApplicationComponent.class
public abstract class HttpProcessorModule {
@BindOKHttp
@Binds
@Singleton //全局单例
abstract IHttpProcessor bindOKHttpProcessor(OKHttpProcessor okHttpProcessor);
@BindVOlley
@Binds
@Singleton //全局单例
abstract IHttpProcessor bindVolleyProcessor(VolleyProcessor volleyProcessor);
}
package com.example.test0530;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BindOKHttp {
}
package com.example.test0530;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BindVOlley {
}