Android OkHttp+Retrofit+RxJava搭建网络访问框架,kotlin协程并发

public Observable apply(Throwable throwable) throws Exception {

//通过这个异常处理,得到用户可以知道的原因

return Observable.error(ExceptionHandle.handleException(throwable));

}

}

还需要写一个基础返回类,在com.llw.network下新建一个BaseResponse,代码如下:

package com.llw.network;

import com.google.gson.annotations.Expose;

import com.google.gson.annotations.SerializedName;

/**

  • 基础返回类

  • @author llw

*/

public class BaseResponse {

//返回码

@SerializedName(“res_code”)

@Expose

public Integer responseCode;

//返回的错误信息

@SerializedName(“res_error”)

@Expose

public String responseError;

}

现在准备工作都做好了,下面就要写这个RxJava的配置了,不过还有一步就是,在NetworkApi中写一个错误码的处理方法,代码如下:

/**

  • 错误码处理

*/

protected static Function<T, T> getAppErrorHandler() {

return new Function<T, T>() {

@Override

public T apply(T response) throws Exception {

//当response返回出现500之类的错误时

if (response instanceof BaseResponse && ((BaseResponse) response).responseCode >= 500) {

//通过这个异常处理,得到用户可以知道的原因

ExceptionHandle.ServerException exception = new ExceptionHandle.ServerException();

exception.code = ((BaseResponse) response).responseCode;

exception.message = ((BaseResponse) response).responseError != null ? ((BaseResponse) response).responseError : “”;

throw exception;

}

return response;

}

};

}

下面终于到了这个RxJava的配置了

/**

  • 配置RxJava 完成线程的切换,如果是Kotlin中完全可以直接使用协程

  • @param observer 这个observer要注意不要使用lifecycle中的Observer

  • @param 泛型

  • @return Observable

*/

public static ObservableTransformer<T, T> applySchedulers(final Observer observer) {

return new ObservableTransformer<T, T>() {

@Override

public ObservableSource apply(Observable upstream) {

Observable observable = upstream

.subscribeOn(Schedulers.io())//线程订阅

.observeOn(AndroidSchedulers.mainThread())//观察Android主线程

.map(NetworkApi.getAppErrorHandler())//判断有没有500的错误,有则进入getAppErrorHandler

.onErrorResumeNext(new HttpErrorHandler());//判断有没有400的错误

//这里还少了对异常

//订阅观察者

observable.subscribe(observer);

return observable;

}

};

}

五、增加拦截器


拦截器中需要打印日志和时间转换,对此需要几个工具类,所以在com.llw.network下新建一个utils包,下面新建一个DateUitl

package com.llw.network.utils;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Calendar;

import java.util.Date;

import java.util.GregorianCalendar;

import java.util.Locale;

public class DateUtil {

//获取当前完整的日期和时间

public static String getNowDateTime() {

SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

return sdf.format(new Date());

}

//获取当前日期

public static String getNowDate() {

SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd”);

return sdf.format(new Date());

}

//前一天

public static String getYesterday(Date date) {

String tomorrow = “”;

Calendar calendar = new GregorianCalendar();

calendar.setTime(date);

calendar.add(Calendar.DATE, -1);

date = calendar.getTime();

SimpleDateFormat formatter = new SimpleDateFormat(“yyyy-MM-dd”);

tomorrow = formatter.format(date);

return tomorrow;

}

//后一天

public static String getTomorrow(Date date) {

String tomorrow = “”;

Calendar calendar = new GregorianCalendar();

calendar.setTime(date);

calendar.add(Calendar.DATE, +1);

date = calendar.getTime();

SimpleDateFormat formatter = new SimpleDateFormat(“yyyy-MM-dd”);

tomorrow = formatter.format(date);

return tomorrow;

}

//获取当前时间

public static String getNowTime() {

SimpleDateFormat sdf = new SimpleDateFormat(“HH:mm:ss”);

return sdf.format(new Date());

}

//获取当前日期(精确到毫秒)

public static String getNowTimeDetail() {

SimpleDateFormat sdf = new SimpleDateFormat(“HH:mm:ss.SSS”);

return sdf.format(new Date());

}

//获取今天是星期几

public static String getWeekOfDate(Date date) {

String[] weekDays = {“星期日”, “星期一”, “星期二”, “星期三”, “星期四”, “星期五”, “星期六”};

Calendar cal = Calendar.getInstance();

cal.setTime(date);

int w = cal.get(Calendar.DAY_OF_WEEK) - 1;

if (w < 0) {

}

w = 0;

return weekDays[w];

}

//计算星期几

private static int getDayOfWeek(String dateTime) {

Calendar cal = Calendar.getInstance();

if (dateTime.equals(“”)) {

cal.setTime(new Date(System.currentTimeMillis()));

} else {

SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd”, Locale.getDefault());

Date date;

try {

date = sdf.parse(dateTime);

} catch (ParseException e) {

date = null;

e.printStackTrace();

}

if (date != null) {

cal.setTime(new Date(date.getTime()));

}

}

return cal.get(Calendar.DAY_OF_WEEK);

}

//根据年月日计算是星期几并与当前日期判断 非昨天、今天、明天 则以星期显示

public static String Week(String dateTime) {

String week = “”;

String yesterday = “”;

String today = “”;

String tomorrow = “”;

yesterday = getYesterday(new Date());

today = getNowDate();

tomorrow = getTomorrow(new Date());

if (dateTime.equals(yesterday)) {

week = “昨天”;

} else if (dateTime.equals(today)) {

week = “今天”;

} else if (dateTime.equals(tomorrow)) {

week = “明天”;

} else {

switch (getDayOfWeek(dateTime)) {

case 1:

week = “星期日”;

break;

case 2:

week = “星期一”;

break;

case 3:

week = “星期二”;

break;

case 4:

week = “星期三”;

break;

case 5:

week = “星期四”;

break;

case 6:

week = “星期五”;

break;

case 7:

week = “星期六”;

break;

}

}

return week;

}

//将时间戳转化为对应的时间(10位或者13位都可以)

public static String formatTime(long time) {

String times = null;

if (String.valueOf(time).length() > 10) {// 10位的秒级别的时间戳

times = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(new Date(time * 1000));

} else {// 13位的秒级别的时间戳

times = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(time);

}

return times;

}

//将时间字符串转为时间戳字符串

public static String getStringTimestamp(String time) {

String timestamp = null;

try {

SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

Long longTime = sdf.parse(time).getTime() / 1000;

timestamp = Long.toString(longTime);

} catch (ParseException e) {

e.printStackTrace();

}

return timestamp;

}

}

同样再建一个KLog类,用于日志打印。

package com.llw.network.utils;

import android.text.TextUtils;

import android.util.Log;

import org.json.JSONArray;

import org.json.JSONException;

import org.json.JSONObject;

/**

  • 自定义日志类

*/

public final class KLog {

private static boolean IS_SHOW_LOG = true;

private static final String DEFAULT_MESSAGE = “execute”;

private static final String LINE_SEPARATOR = System.getProperty(“line.separator”);

private static final int JSON_INDENT = 4;

private static final int V = 0x1;

private static final int D = 0x2;

private static final int I = 0x3;

private static final int W = 0x4;

private static final int E = 0x5;

private static final int A = 0x6;

private static final int JSON = 0x7;

public static void init(boolean isShowLog) {

IS_SHOW_LOG = isShowLog;

}

public static void v() {

printLog(V, null, DEFAULT_MESSAGE);

}

public static void v(String msg) {

printLog(V, null, msg);

}

public static void v(String tag, String msg) {

printLog(V, tag, msg);

}

public static void d() {

printLog(D, null, DEFAULT_MESSAGE);

}

public static void d(String msg) {

printLog(D, null, msg);

}

public static void d(String tag, String msg) {

printLog(D, tag, msg);

}

public static void i() {

printLog(I, null, DEFAULT_MESSAGE);

}

public static void i(String msg) {

printLog(I, null, msg);

}

public static void i(String tag, String msg) {

printLog(I, tag, msg);

}

public static void w() {

printLog(W, null, DEFAULT_MESSAGE);

}

public static void w(String msg) {

printLog(W, null, msg);

}

public static void w(String tag, String msg) {

printLog(W, tag, msg);

}

public static void e() {

printLog(E, null, DEFAULT_MESSAGE);

}

public static void e(String msg) {

printLog(E, null, msg);

}

public static void e(String tag, String msg) {

printLog(E, tag, msg);

}

public static void a() {

printLog(A, null, DEFAULT_MESSAGE);

}

public static void a(String msg) {

printLog(A, null, msg);

}

public static void a(String tag, String msg) {

printLog(A, tag, msg);

}

public static void json(String jsonFormat) {

printLog(JSON, null, jsonFormat);

}

public static void json(String tag, String jsonFormat) {

printLog(JSON, tag, jsonFormat);

}

private static void printLog(int type, String tagStr, String msg) {

if (!IS_SHOW_LOG) {

return;

}

StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

int index = 4;

String className = stackTrace[index].getFileName();

String methodName = stackTrace[index].getMethodName();

int lineNumber = stackTrace[index].getLineNumber();

String tag = (tagStr == null ? className : tagStr);

methodName = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);

StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append(“[ (”).append(className).append(“:”).append(lineNumber).append(“)#”).append(methodName).append(" ] ");

if (msg != null && type != JSON) {

stringBuilder.append(msg);

}

String logStr = stringBuilder.toString();

switch (type) {

case V:

Log.v(tag, logStr);

break;

case D:

Log.d(tag, logStr);

break;

case I:

Log.i(tag, logStr);

break;

case W:

Log.w(tag, logStr);

break;

case E:

Log.e(tag, logStr);

break;

case A:

Log.wtf(tag, logStr);

break;

case JSON: {

if (TextUtils.isEmpty(msg)) {

Log.d(tag, “Empty or Null json content”);

return;

}

String message = null;

try {

if (msg.startsWith(“{”)) {

JSONObject jsonObject = new JSONObject(msg);

message = jsonObject.toString(JSON_INDENT);

} else if (msg.startsWith(“[”)) {

JSONArray jsonArray = new JSONArray(msg);

message = jsonArray.toString(JSON_INDENT);

}

} catch (JSONException e) {

e(tag, e.getCause().getMessage() + “\n” + msg);

return;

}

printLine(tag, true);

message = logStr + LINE_SEPARATOR + message;

String[] lines = message.split(LINE_SEPARATOR);

StringBuilder jsonContent = new StringBuilder();

for (String line : lines) {

jsonContent.append("║ ").append(line).append(LINE_SEPARATOR);

}

Log.d(tag, jsonContent.toString());

printLine(tag, false);

}

break;

default:

break;

}

}

private static void printLine(String tag, boolean isTop) {

if (isTop) {

Log.d(tag, “╔═══════════════════════════════════════════════════════════════════════════════════════”);

} else {

Log.d(tag, “╚═══════════════════════════════════════════════════════════════════════════════════════”);

}

}

}

在com.llw.network下新建一个Interceptor包,包下新建一个RequestInterceptor类,这是一个请求拦截器,里面的代码如下:

package com.llw.network.interceptor;

import com.llw.network.INetworkRequiredInfo;

import com.llw.network.utils.DateUtil;

import java.io.IOException;

import okhttp3.Interceptor;

import okhttp3.Request;

import okhttp3.Response;

/**

  • 请求拦截器

  • @author llw

*/

public class RequestInterceptor implements Interceptor {

/**

  • 网络请求信息

*/

private INetworkRequiredInfo iNetworkRequiredInfo;

public RequestInterceptor(INetworkRequiredInfo iNetworkRequiredInfo){

this.iNetworkRequiredInfo = iNetworkRequiredInfo;

}

/**

  • 拦截

*/

@Override

public Response intercept(Chain chain) throws IOException {

String nowDateTime = DateUtil.getNowDateTime();

//构建器

Request.Builder builder = chain.request().newBuilder();

//添加使用环境

builder.addHeader(“os”,“android”);

//添加版本号

builder.addHeader(“appVersionCode”,this.iNetworkRequiredInfo.getAppVersionCode());

//添加版本名

builder.addHeader(“appVersionName”,this.iNetworkRequiredInfo.getAppVersionName());

//添加日期时间

builder.addHeader(“datetime”,nowDateTime);

//返回

return chain.proceed(builder.build());

}

}

还有一个返回拦截器或者说是响应拦截器。

package com.llw.network.interceptor;

import com.llw.network.utils.KLog;

import java.io.IOException;

import okhttp3.Interceptor;

import okhttp3.Response;

/**

  • 返回拦截器(响应拦截器)

  • @author llw

*/

public class ResponseInterceptor implements Interceptor {

private static final String TAG = “ResponseInterceptor”;

/**

  • 拦截

*/

@Override

public Response intercept(Chain chain) throws IOException {

long requestTime = System.currentTimeMillis();

Response response = chain.proceed(chain.request());

KLog.i(TAG, “requestSpendTime=” + (System.currentTimeMillis() - requestTime) + “ms”);

return response;

}

}

这里面也很简单就是可记录当前这个接口的请求耗费时长,这个时间在网速正常的情况下自然是越短越好,当然这个就是后期的网络方面的优化了。

那么这两个拦截器有了,下面就他们放到OkHttp中,打开NetworkApi

在这里插入图片描述

现在这个拦截器就会在请求网络时生效了。

六、自定义Observer


在上面的代码中完成了对OkHttp的优化,OkHttp负责网络访问,使用Retrofit发起网络请求,使用RxJava处理返回结果,在上面只是做了线程的切换和错误码的处理,所以还需要的返回做一个处理,下面在com.llw.network下新建一个observer包,该包下新建一个BaseObserver的抽象类,里面代码如下:

package com.llw.network.observer;

import io.reactivex.Observer;

import io.reactivex.disposables.Disposable;

/**

  • 自定义Observer

  • @author llw

*/

public abstract class BaseObserver implements Observer {

//开始

@Override

public void onSubscribe(Disposable d) {

}

//继续

@Override

public void onNext(T t) {

onSuccess(t);

}

//异常

@Override

public void onError(Throwable e) {

onFailure(e);

}

//完成

@Override

public void onComplete() {

}

//成功

public abstract void onSuccess(T t);

//失败

public abstract void onFailure(Throwable e);

}

这里我并没有重写Observer的所有方法,只用了两个,onNext和onError。

七、配置网络环境


在日常开发中,常常会有多个开发环境,比如测试环境、正式环境。他们的区别其实就是前面的地址不同而已,后面的参数都是一样的。举个例子,加入你是Android开发,你面对了两个后台开发,在项目初期后台的服务器都是在自己的电脑上,因此你需要配置他们电脑的ip地址才能去访问他们所写的接口API,普通做法就是对接A的接口时使用A的ip,对接B的接口时使用B的ip,你可能会觉得不就是修改一行代码的事情吗,不麻烦,那假如让你打包出来测试呢?因为一个APP的出现不能不去测试,开发的话要是能信,还要测试干什么?这是我一个测试朋友说的,一时间我竟无法反驳。因此为了避免不断需要我们去根据不同的网络环境打包测试,就体现出来这个网络环境的重要性了,说了这么多也是一个建议,当然你是否采纳取决于自己,起码我是这么做的。

在com.llw.network下新建一个environment包。包下新建一个NetworkEnvironmentActivity,然后先不管它,因为还需要配置一些东西才行。在res下创建一个layout文件下,在这个文件夹下创建一个activity_network_environment.xml文件,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:id=“@+id/content”

android:layout_width=“match_parent”

android:layout_height=“match_parent” />

在这里插入图片描述

然后在values下新建一个network_array.xml文件,用于网络配置数组参数,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

正式

测试

1

2

这里我配置了两个环境,一个正式一个测试,实际开发中可能会更多,可根据实际情况进行增减。

然后在drawable下新建一个ic_network_settings.xml,这是一个图标,用路径写的。

<vector xmlns:android=“http://schemas.android.com/apk/res/android”

android:width=“56dp”

android:height=“56dp”

android:viewportWidth=“56”

android:viewportHeight=“56”>

<path

android:fillColor=“#FF000000”

android:pathData=“M8,41.08V2c0,-0.553 -0.448,-1 -1,-1S6,1.447 6,2v39.08C2.613,41.568 0,44.481 0,48c0,3.859 3.14,7 7,7s7,-3.141 7,-7C14,44.481 11.387,41.568 8,41.08zM7,53c-2.757,0 -5,-2.243 -5,-5s2.243,-5 5,-5s5,2.243 5,5S9.757,53 7,53z”/>

<path

android:fillColor=“#FF000000”

android:pathData=“M29,20.695V2c0,-0.553 -0.448,-1 -1,-1s-1,0.447 -1,1v18.632c-3.602,0.396 -6.414,3.456 -6.414,7.161s2.812,6.765 6.414,7.161V54c0,0.553 0.448,1 1,1s1,-0.447 1,-1V34.891c3.4,-0.577 6,-3.536 6,-7.098S32.4,21.272 29,20.695zM27.793,33c-2.871,0 -5.207,-2.336 -5.207,-5.207s2.335,-5.207 5.207,-5.207S33,24.922 33,27.793S30.664,33 27.793,33z”/>

<path

android:fillColor=“#FF000000”

android:pathData=“M56,8c0,-3.859 -3.14,-7 -7,-7s-7,3.141 -7,7c0,3.519 2.613,6.432 6,6.92V54c0,0.553 0.448,1 1,1s1,-0.447 1,-1V14.92C53.387,14.432 56,11.519 56,8zM49,13c-2.757,0 -5,-2.243 -5,-5s2.243,-5 5,-5s5,2.243 5,5S51.757,13 49,13z”/>

然后在strings.xml中增加一个值。

网络环境设置

您已经更改了网络环境,在您退出当前页面的时候APP将会重启切换环境!

在这里插入图片描述

下面对网络进行一些配置,在Android9.0及以后版本,默认使用Https访问网络,这导致了不能使用Http,因此要配置允许使用Http,在res下新建一个xml文件夹,在这个文件夹下新建一个network_security_config.xml,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

然后在这个xml文件夹下再建一个environment_preference.xml文件,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>

<ListPreference

android:defaultValue=“1”

android:entries=“@array/environmentName”

android:entryValues=“@array/environmentValues”

android:icon=“@drawable/ic_network_settings”

android:key=“network_environment”

android:summary=“请您选择您需要使用的网络环境,选择完后会重启APP生效”

android:title=“设置网络环境” />

这里默认的值为1,也就是正式环境。现在关于xml就配置完了,该进入这个NetworkEnvironmentActivity里面去写代码了,首先继承AppCompatActivity,重写父类的onCreate方法,然后设置布局。现在看起来这个Activity就和常规的Activity差不多了。

package com.llw.network.environment;

import android.os.Bundle;

import androidx.annotation.Nullable;

import androidx.appcompat.app.AppCompatActivity;

import com.llw.network.R;

/**

  • 设置网络环境Activity

  • @author llw

*/

public class NetworkEnvironmentActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_network_environment);

}

}

当然这还是刚开始,下面一步一步完善这个Activity,首先增加两个成员变量。

//网络环境

public static final String NETWORK_ENVIRONMENT = “network_environment”;

//当前网络环境

private static String mCurrentNetworkEnvironment = “”;

下面会用到缓存,键就是NETWORK_ENVIRONMENT,常规这种键都是大写的。

先在NetworkEnvironmentActivity中创建一个内部类MyPreferenceFragment继承PreferenceFragmentCompat并实现Preference.OnPreferenceChangeListener。

/**

  • 内部缓存变化监听类

*/

public static class MyPreferenceFragment extends PreferenceFragmentCompat

implements Preference.OnPreferenceChangeListener {

//创建缓存

@Override

public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {

//这个相当于Activity的setContentView,从资源文件中添Preferences ,选择的值将会自动保存到SharePreferences

addPreferencesFromResource(R.xml.environment_preference);

//设置缓存变化监听 , 通过键来设置监听

findPreference(NETWORK_ENVIRONMENT).setOnPreferenceChangeListener(this);

}

//缓存变化

@Override

public boolean onPreferenceChange(Preference preference, Object newValue) {

if (!mCurrentNetworkEnvironment.equalsIgnoreCase(String.valueOf(newValue))) {

//当前值与缓存中不一致时,说明切换了网络,这时提醒一下

Toast.makeText(getContext(), R.string.network_change_tip, Toast.LENGTH_SHORT).show();

}

return true;

}

}

通过这个类,定义xml文件中,的操作方式,ListPreferenc这个控件中,默认是正式环境,当你修改之后,会将你修改的值存到缓存中,然后会进入这个缓存变化的回调中,此时提醒一下开发者,当然此时只是更换了缓存信息而已,此时应该退出当前应用,再重启,重启时读取缓存中的值,根据这个值去使用不同的环境,那么为了让这个过程显得不那么突兀,可以在页面返回的监听中做判断。

/**

  • 页面返回

*/

@Override

public void onBackPressed() {

//获取缓存对象

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);

//通过键获取缓存则,没有则使用默认值

String value = preferences.getString(NETWORK_ENVIRONMENT, “1”);

if (!mCurrentNetworkEnvironment.equalsIgnoreCase(value)) {

//不一致.说明有修改,从操作系统中结束掉当前程序的进程

android.os.Process.killProcess(android.os.Process.myPid());

} else {

//一致 没有修改则关闭当前页面

finish();

}

}

onBackPressed可以监听页面的返回按钮的点击事件,我在这里判断是否有修改网络环境,因为缓存值修改就意味着网络环境修改,如果已经修改过则在返回页面时结束当前程序的进程,如果没有修改只是关闭当前的Activity而已。

而假如要在启动App时判断当前环境是否为正式环境时,还是需要去缓存来对比的,因此可以再写一个方法来判断当前是否为正式环境,方法如下:

/**

  • 是否为正式环境

*/

public static boolean isFormalEnvironment(Application application) {

//获取当前应用的缓存

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);

String networkEnvironment = preferences.getString(NETWORK_ENVIRONMENT, “1”);

return “1”.equalsIgnoreCase(networkEnvironment);

}

因为当前只有正式和测试两种情况,因此可以用boolean就可以,多种情况你可以返回一个key的结果,每个key对应不同的网络,自己区分好就行。

最后在onCreate中配置Fragment的replace

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_network_environment);

getSupportFragmentManager()

.beginTransaction()

.replace(R.id.content, new MyPreferenceFragment())

.commit();

//获取默认缓存

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);

//如果没有值就默认为 “1” 在这里 1 表示正式环境

mCurrentNetworkEnvironment = preferences.getString(NETWORK_ENVIRONMENT,“1”);

}

这样这个Activity就写完了,别忘了在AndroidManifest.xml中配置

<manifest xmlns:android=“http://schemas.android.com/apk/res/android”

package=“com.llw.network”>

<activity

android:name=“.environment.NetworkEnvironmentActivity”

android:label=“@string/network_environment_setting”

android:screenOrientation=“portrait” />

但是网络配置这一步还没有结束,之前在NetworkApi中配置了mBaseUrl这个成员变量,还记得吗?之前可是一直没有赋值的,我相信你已经猜到了,更改网络环境,实际上就是在更改mBaseUrl的值,只不过更改之前要根据缓存判断一下。

那么在NetworkApi中再增加一个成员变量

//是否为正式环境

private static boolean isFormal = true;

下面在NetworkApi中新增一个初始化的方法,代码如下:

/**

  • 初始化

*/

public static void init(INetworkRequiredInfo networkRequiredInfo) {

iNetworkRequiredInfo = networkRequiredInfo;

//当初始化这个NetworkApi时,会判断当前App的网络环境

isFormal = NetworkEnvironmentActivity.isFormalEnvironment(networkRequiredInfo.getApplicationContext());

if (isFormal) {

//正式环境

mBaseUrl = “http://service.picasso.adesk.com”;

} else {

//测试环境

mBaseUrl = “https://cn.bing.com”;

}

}

同样还要创建一个Service的实例方法,代码如下:

/**

  • 创建serviceClass的实例

*/

public static T createService(Class serviceClass) {

return getRetrofit(serviceClass).create(serviceClass);

}

OK,到目前为止,NetworkApi终于是写完了。

下面这个该进入使用环节了,回到app模块。

八、使用网络框架


在这里插入图片描述

目前app模块下只有这一个孤零零的MainActivity。首先在app下的com.llw.network下新建一个application包,(在实际开发中尽量要避免包名重复的情况),在这个包下创建一个NetworkRequiredInfo类,然后实现network模块下的INetworkRequiredInfo接口。

在这里插入图片描述

你会发现,这个报红,这时因为你没有添加network模块的依赖,那么有三种方式可以添加,

1. 添加网络模块依赖

① 当前项目添加

第一种:

鼠标点击这个报红处,然后使用Alt+Enter,会出现如下弹窗,点击第一项Add dependency on module ‘network’,意思就是添加network模块的依赖。

在这里插入图片描述

点击之后,等待即可

在这里插入图片描述

然后发现报错了,这个报错是为什么呢?

在这里插入图片描述

你打开app的build.gradle就知道了,如下图所示:

在这里插入图片描述

我这里解释一下是为什么,随着Gradle版本的更新,以前的一些使用方式就弃用了,比如这个compile就过时了,因此在高版本中可以替换为implementation和api。那么将compile替换成为implementation之后点击右上角的Sync Now进行同步。

在这里插入图片描述

这样就编译成功了,上面通过Alt + Enter的方式虽然不用我们改动,但是这个内部机制还是低版本的,它做的无非就是加一句话而已,那么我们也可以自己来加不是吗?

第二种:

打开app的build.gradle,在dependencies{}闭包下添加如下依赖:

//依赖网络模块

implementation project(path: ‘:network’)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

【Android高级架构视频学习资源】

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
_FFFFFF,t_70)

我这里解释一下是为什么,随着Gradle版本的更新,以前的一些使用方式就弃用了,比如这个compile就过时了,因此在高版本中可以替换为implementation和api。那么将compile替换成为implementation之后点击右上角的Sync Now进行同步。

在这里插入图片描述

这样就编译成功了,上面通过Alt + Enter的方式虽然不用我们改动,但是这个内部机制还是低版本的,它做的无非就是加一句话而已,那么我们也可以自己来加不是吗?

第二种:

打开app的build.gradle,在dependencies{}闭包下添加如下依赖:

//依赖网络模块

implementation project(path: ‘:network’)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-hRS9jCl8-1712604326738)]
[外链图片转存中…(img-C0JWEpvt-1712604326739)]
[外链图片转存中…(img-7161wNFj-1712604326739)]
[外链图片转存中…(img-SE743cVJ-1712604326739)]
[外链图片转存中…(img-MQFpcARr-1712604326740)]
[外链图片转存中…(img-i70VMuxp-1712604326740)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-sFScWwEE-1712604326741)]

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-h5J0gnqk-1712604326741)]

【Android高级架构视频学习资源】

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-bBdb06dj-1712604326741)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值