import android.os.Bundle;

/**

  • UI回调接口

*/

public interface UiCallBack {

//初始化savedInstanceState

void initBeforeView(Bundle savedInstanceState);

//初始化

void initData(Bundle savedInstanceState);

//布局

int getLayoutId();

}

base包,新创建一个BaseView接口

在这里插入图片描述

代码如下:

package com.llw.mvplibrary.base;

/**

  • 只是一个接口BaseView ,里面可以自由定制

*/

public interface BaseView {

}

base包下面创建一个BasePresenter

在这里插入图片描述

代码如下:

package com.llw.mvplibrary.base;

import com.llw.mvplibrary.base.BaseView;

import java.lang.ref.WeakReference;

/**

  • Presenter基类 操作视图View

  • @param

*/

public class BasePresenter {

private WeakReference mWeakReference;

/**

  • 关联view

  • @param v

*/

public void attach(V v){

mWeakReference=new WeakReference(v);

}

/**

  • 分离view

  • @param v

*/

public void detach(V v){

if (mWeakReference!=null){

mWeakReference.clear();

mWeakReference=null;

}

}

/**

  • 获取view

  • @return

*/

public V getView(){

if (mWeakReference!=null){

return mWeakReference.get();

}

return null;

}

}

接下来在base包下面创建一个网络请求返回解析基类 BaseResponse

在这里插入图片描述

代码如下:

package com.llw.mvplibrary.base;

/**

  • @ClassDest: 网络请求返回解析基类

*/

public class BaseResponse {

/**

  • code : 200

  • msg : incorrect password

  • data : null

*/

private int code;

private String msg;

private Object data;

public int getCode() {

return code;

}

public void setCode(int code) {

this.code = code;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public Object getData() {

return data;

}

public void setData(Object data) {

this.data = data;

}

}

接下来在base包下面创建BaseActivity ,不需要MVP的Activity普通的Activity直接继承即可使用,这用主要是用于管理Acitivity

在这里插入图片描述

代码如下,这个里面还有进一步优化的空间,后面会提到的。

package com.llw.mvplibrary.base;

import android.app.Activity;

import android.os.Bundle;

import androidx.annotation.Nullable;

import androidx.appcompat.app.AppCompatActivity;

import com.llw.mvplibrary.BaseApplication;

import com.llw.mvplibrary.kit.KnifeKit;

import butterknife.Unbinder;

/**

  • 用于不需要请求网络接口的Activity

*/

public abstract class BaseActivity extends AppCompatActivity implements UiCallBack {

protected Activity context;

private Unbinder unbinder;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

initBeforeView(savedInstanceState);

this.context = this;

//添加继承这个BaseActivity的Activity

BaseApplication.getActivityManager().addActivity(this);

if (getLayoutId() > 0) {

setContentView(getLayoutId());

unbinder = KnifeKit.bind(this);

}

initData(savedInstanceState);

}

@Override

public void initBeforeView(Bundle savedInstanceState) {

}

@Override

protected void onStart() {

super.onStart();

}

}

既然有了BaseActivity,当然也要有BaseFragment,

在base包下创建BaseFragment意思与BaseActivity接近

在这里插入图片描述

代码如下:

package com.llw.mvplibrary.base;

import android.app.Activity;

import android.content.Context;

import android.os.Bundle;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import androidx.annotation.Nullable;

import androidx.fragment.app.Fragment;

import com.llw.mvplibrary.kit.KnifeKit;

import butterknife.Unbinder;

/**

  • 用于不需要请求网络接口的BaseFragment

*/

public abstract class BaseFragment extends Fragment implements UiCallBack {

protected View rootView;

protected LayoutInflater layoutInflater;

protected Activity context;

private Unbinder unbinder;

@Override

public void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

initBeforeView(savedInstanceState);

}

@Nullable

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

layoutInflater = inflater;

if (rootView == null) {

rootView = inflater.inflate(getLayoutId(), null);

unbinder = KnifeKit.bind(this, rootView);

} else {

ViewGroup viewGroup = (ViewGroup) rootView.getParent();

if (viewGroup != null) {

viewGroup.removeView(rootView);

}

}

return rootView;

}

@Override

public void onActivityCreated(@Nullable Bundle savedInstanceState) {

super.onActivityCreated(savedInstanceState);

initData(savedInstanceState);

}

@Override

public void onAttach(Context context) {

super.onAttach(context);

if (context instanceof Activity) {

this.context = (Activity) context;

}

}

@Override

public void onDetach() {

super.onDetach();

context = null;

}

@Override

public void initBeforeView(Bundle savedInstanceState) {

}

}

⑦ 创建mvp包(以及包下的Activity和Fragment)

base需要的东西已经写完了。接下来创建一个mvp包,包下创建MvpActivity

在这里插入图片描述

代码如下:

package com.llw.mvplibrary.mvp;

import android.os.Bundle;

import com.llw.mvplibrary.base.BaseActivity;

import com.llw.mvplibrary.base.BasePresenter;

import com.llw.mvplibrary.base.BaseView;

/**

  • 适用于需要访问网络接口的Activity

*/

public abstract class MvpActivity

extends BaseActivity {

protected P mPresent;

@Override

public void initBeforeView(Bundle savedInstanceState) {

mPresent=createPresent();

mPresent.attach((BaseView) this);

}

protected abstract P createPresent();

@Override

public void onDestroy() {

super.onDestroy();

mPresent.detach((BaseView) this);

}

}

同样在mvp包下创建MvpFragment

在这里插入图片描述

代码如下:

package com.llw.mvplibrary.mvp;

import android.os.Bundle;

import com.llw.mvplibrary.base.BaseFragment;

import com.llw.mvplibrary.base.BasePresenter;

import com.llw.mvplibrary.base.BaseView;

/**

  • 适用于需要访问网络接口的Fragment

*/

public abstract class MvpFragment

extends BaseFragment {

protected P mPresent;

@Override

public void initBeforeView(Bundle savedInstanceState) {

mPresent=createPresent();

mPresent.attach((BaseView) this);

}

@Override

public void onDetach() {

super.onDetach();

if (mPresent!=null){

mPresent.detach((BaseView) this);

}

}

protected abstract P createPresent();

}

⑧ 创建net包(封装OKHttp,重写CallBack)

mvp包下的内容写完了,接下来配置网络访问

先创建一个net包 ,在这个包下新建一个ServiceGenerator

在这里插入图片描述

代码如下:

package com.llw.mvplibrary.net;

import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;

import okhttp3.logging.HttpLoggingInterceptor;

import retrofit2.Retrofit;

import retrofit2.converter.gson.GsonConverterFactory;

/**

  • 服务构建器 API服务设置在里面

*/

public class ServiceGenerator {

//https://free-api.heweather.net/s6/weather/now?key=3086e91d66c04ce588a7f538f917c7f4&location=深圳

//将上方的API接口地址进行拆分得到不变的一部分,实际开发中可以将这一部分作为服务器的ip访问地址

public static String BASE_URL = “https://free-api.heweather.net”;//地址

//创建服务 参数就是API服务

public static T createService(Class serviceClass) {

//创建OkHttpClient构建器对象

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();

//设置请求超时的时间,这里是10秒

okHttpClientBuilder.connectTimeout(10000, TimeUnit.MILLISECONDS);

//消息拦截器 因为有时候接口不同在排错的时候 需要先从接口的响应中做分析。利用了消息拦截器可以清楚的看到接口返回的所有内容

HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();

//setlevel用来设置日志打印的级别,共包括了四个级别:NONE,BASIC,HEADER,BODY

//BASEIC:请求/响应行

//HEADER:请求/响应行 + 头

//BODY:请求/响应航 + 头 + 体

httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

//为OkHttp添加消息拦截器

okHttpClientBuilder.addInterceptor(httpLoggingInterceptor);

//在Retrofit中设置httpclient

Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)//设置地址 就是上面的固定地址,如果你是本地访问的话,可以拼接上端口号 例如 +“:8080”

.addConverterFactory(GsonConverterFactory.create())//用Gson把服务端返回的json数据解析成实体

.client(okHttpClientBuilder.build())//放入OKHttp,之前说过retrofit是对OkHttp的进一步封装

.build();

return retrofit.create(serviceClass);//返回这个创建好的API服务

}

}

接下来重写Callback,在,net包下新建NetCallBack

在这里插入图片描述

代码如下:

package com.llw.mvplibrary.net;

import android.util.Log;

import com.google.gson.Gson;

import com.llw.mvplibrary.base.BaseResponse;

import retrofit2.Call;

import retrofit2.Callback;

import retrofit2.Response;

/**

  • 网络请求回调

  • @param

*/

public abstract class NetCallBack implements Callback {//这里实现了retrofit2.Callback

//访问成功回调

@Override

public void onResponse(Call call, Response response) {//数据返回

if (response != null && response.body() != null && response.isSuccessful()) {

BaseResponse baseResponse = new Gson().fromJson(new Gson().toJson(response.body()), BaseResponse.class);

if (baseResponse.getCode() == 404) {//404

Log.e(“Warn”,baseResponse.getData().toString());

}else if(baseResponse.getCode() == 500) {//500

Log.e(“Warn”,baseResponse.getData().toString());

} else {//无异常则返回数据

onSuccess(call, response);

Log.e(“Warn”,“其他情况”);

}

} else {

onFailed();

}

}

//访问失败回调

@Override

public void onFailure(Call call, Throwable t) {

onFailed();

}

//数据返回

public abstract void onSuccess(Call call, Response response);

//失败异常

public abstract void onFailed();

}

5. app使用MVP


至此,MVP框架就搭建完成了,接下来回到app项目中在com.llw.goodweather包下创建一个api包,在这个包下新建一个ApiService接口

① 创建API管理服务接口ApiService

在这里插入图片描述

代码如下:

package com.llw.goodweather.api;

import com.llw.goodweather.bean.TodayResponse;

import retrofit2.Call;

import retrofit2.http.GET;

import retrofit2.http.Query;

/**

  • API服务接口

*/

public interface ApiService {

/**

  • 当天天气查询

  • https://free-api.heweather.net/s6/weather/now?key=3086e91d66c04ce588a7f538f917c7f4&location=深圳

  • 将地址进一步拆分,将可变的一部分放在注解@GET的地址里面,其中

  • /s6/weather/now?key=3086e91d66c04ce588a7f538f917c7f4 这一部分在这个接口中又是不变的,变的是location的值

  • 所以将location的参数放入@Query里面,因为是使用的GET请求,所以里面的内容会拼接到地址后面,并且自动会加上 & 符号

  • Call是retrofit2框架里面的,这个框架是对OKHttp的进一步封装,会让你的使用更加简洁明了,里面放入之前通过接口返回

  • 的JSON字符串生成返回数据实体Bean,Retrofit支持Gson解析实体类,所以,后面的返回值就不用做解析了。

  • getTodayWeather是这个接口的方法名。这样说应该很清楚了吧

  • @param location 区/县

  • @return

*/

@GET(“/s6/weather/now?key=3086e91d66c04ce588a7f538f917c7f4”)

Call getTodayWeather(@Query(“location”) String location);

}

这里你要注意一点key的值用你自己的应用的KEY

② 订阅接口服务,处理API请求返回数据

接下来新建contract包,创建一个订阅器WeatherContract

在这里插入图片描述

代码如下:

package com.llw.goodweather.contract;

import android.content.Context;

import com.llw.goodweather.api.ApiService;

import com.llw.goodweather.bean.TodayResponse;

import com.llw.mvplibrary.base.BasePresenter;

import com.llw.mvplibrary.base.BaseView;

import com.llw.mvplibrary.net.NetCallBack;

import com.llw.mvplibrary.net.ServiceGenerator;

import retrofit2.Call;

import retrofit2.Response;

/**

  • 天气订阅器

*/

public class WeatherContract {

public static class WeatherPresenter extends BasePresenter {

/**

  • 当日天气

  • @param context

  • @param location 区/县

*/

public void todayWeather(final Context context, String location) {

//得到构建之后的网络请求服务,这里的地址已经拼接完成,只差一个location了

ApiService service = ServiceGenerator.createService(ApiService.class);

//设置请求回调 NetCallBack是重写请求回调

service.getTodayWeather(location).enqueue(new NetCallBack() {

//成功回调

@Override

public void onSuccess(Call call, Response response) {

if (getView() != null) {//当视图不会空时返回请求数据

getView().getTodayWeatherResult(response);

}

}

//失败回调

@Override

public void onFailed() {

if (getView() != null) {//当视图不会空时获取错误信息

getView().getDataFailed();

}

}

});

}

}

public interface IWeatherView extends BaseView {

//将数据放入实体

void getTodayWeatherResult(Response response);

//错误返回

void getDataFailed();

}

}

③ 继承mvplibrary中的BaseApplication

接下来,在项目的com.llw.goodweather包下,新建一个WeatherApplication类继承模块中BaseApplication

在这里插入图片描述

代码如下:

package com.llw.goodweather;

import android.app.Activity;

import android.app.Dialog;

import android.content.Context;

import android.content.res.Configuration;

import android.os.Bundle;

import android.os.Handler;

import android.webkit.WebView;

import com.llw.mvplibrary.BaseApplication;

import com.llw.mvplibrary.utils.ActivityManager;

import com.scwang.smartrefresh.layout.SmartRefreshLayout;

import com.scwang.smartrefresh.layout.api.DefaultRefreshFooterCreator;

import com.scwang.smartrefresh.layout.api.DefaultRefreshHeaderCreator;

import com.scwang.smartrefresh.layout.api.RefreshFooter;

import com.scwang.smartrefresh.layout.api.RefreshHeader;

import com.scwang.smartrefresh.layout.api.RefreshLayout;

import com.scwang.smartrefresh.layout.footer.ClassicsFooter;

import com.scwang.smartrefresh.layout.header.ClassicsHeader;

public class WeatherApplication extends BaseApplication {

/**

  • 应用实例

*/

public static WeatherApplication weatherApplication;

private static Context context;

private static ActivityManager activityManager;

private static Activity sActivity;

public static Context getMyContext() {

return weatherApplication == null ? null : weatherApplication.getApplicationContext();

}

private Handler myHandler;

public Handler getMyHandler() {

return myHandler;

}

public void setMyHandler(Handler handler) {

myHandler = handler;

}

@Override

public void onCreate() {

super.onCreate();

activityManager = new ActivityManager();

context = getApplicationContext();

weatherApplication = this;

this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

@Override

public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

}

@Override

public void onActivityStarted(Activity activity) {

sActivity = activity;

}

@Override

public void onActivityResumed(Activity activity) {

}

@Override

public void onActivityPaused(Activity activity) {

}

@Override

public void onActivityStopped(Activity activity) {

}

@Override

public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

}

@Override

public void onActivityDestroyed(Activity activity) {

}

});

}

public static ActivityManager getActivityManager() {

return activityManager;

}

@Override

public void onConfigurationChanged(Configuration newConfig) {

super.onConfigurationChanged(newConfig);

}

//static 代码段可以防止内存泄露

static {

//设置全局的Header构建器

SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() {

@Override

public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {

layout.setPrimaryColorsId(android.R.color.darker_gray, android.R.color.black);//全局设置主题颜色

return new ClassicsHeader(context);//.setTimeFormat(new DynamicTimeFormat(“更新于 %s”));//指定为经典Header,默认是 贝塞尔雷达Header

}

});

//设置全局的Footer构建器

SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() {

@Override

public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {

//指定为经典Footer,默认是 BallPulseFooter

return new ClassicsFooter(context).setDrawableSize(20);

}

});

}

}

④ 配置AndroidManifest.xml文件

接下来在AndroidManifest.xml文件中配置WeatherApplication

在这里插入图片描述

由于Android9.0以后网络访问默认是https了,导致访问http类型的API接口访问不了,所以要配置项目允许访问http,所以在res文件下面新建一个xml的文件夹,在这个文件夹下新建名为的network_security_config.xml的网络配置文件,里面的配置代码如下:

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

接下来在AndroidManifest.xml文件中配置

在这里插入图片描述

现在你可以运行一下,看你的项目有没有问题,早出现问题早解决。

现在框架已经搭好了,不过页面布局还没有写好的,所以要写一下页面了。

⑤ 编辑布局文件

activity_main.xml

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

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

xmlns:app=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:gravity=“center”

android:fitsSystemWindows=“true”

android:background=“@drawable/pic_bg”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:context=“.MainActivity”>

<RelativeLayout

android:layout_width=“match_parent”

android:layout_height=“match_parent”>

<LinearLayout

android:background=“#000”

android:alpha=“0.3”

android:layout_width=“match_parent”

android:layout_height=“match_parent”/>

<LinearLayout

android:orientation=“vertical”

android:layout_width=“match_parent”

android:layout_height=“match_parent”>

<androidx.appcompat.widget.Toolbar

android:id=“@+id/toolbar”

android:layout_width=“match_parent”

android:layout_height=“?attr/actionBarSize”

app:contentInsetLeft=“16dp”

app:popupTheme=“@style/AppTheme.PopupOverlay”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_gravity=“center”

android:textSize=“16sp”

android:textColor=“#FFF”

android:text=“城市天气” />

</androidx.appcompat.widget.Toolbar>

<LinearLayout

android:gravity=“center_horizontal”

android:orientation=“vertical”

android:layout_width=“match_parent”

android:layout_height=“match_parent”>

<TextView

android:paddingLeft=“16dp”

android:paddingTop=“12dp”

android:id=“@+id/tv_info”

android:textColor=“#FFF”

android:textSize=“18sp”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”/>

<LinearLayout

android:gravity=“top|center_horizontal”

android:layout_marginTop=“20dp”

android:orientation=“horizontal”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”>

<TextView

android:id=“@+id/tv_temperature”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“0”

android:textColor=“#FFF”

android:textSize=“60sp” />

<TextView

android:layout_width=“wrap_content”

android:layout_height=“match_parent”

android:text=“℃”

android:textColor=“#FFF”

android:textSize=“24sp” />

<TextView

android:layout_marginTop=“12dp”

android:id=“@+id/tv_low_height”

android:textColor=“#FFF”

android:textSize=“@dimen/sp_14”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

<TextView

android:layout_marginTop=“20dp”

android:id=“@+id/tv_city”

android:textColor=“#FFF”

android:text=“城市”

android:textSize=“20sp”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

<TextView

android:layout_marginTop=“8dp”

android:id=“@+id/tv_old_time”

android:textColor=“#FFF”

android:text=“上次更新时间:”

android:textSize=“@dimen/sp_12”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”/>

背景图

在这里插入图片描述

修改res文件下styles.xml文件

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐