Android 天气APP(四)搭建MVP框架与使用
上一篇:Android 天气APP(三)访问天气API与数据请求
现在这样固然符合网络请求的标准,结果也得到了,但是这只是一个接口而已,我们用了这么多代码,那假如这个页面上还有好几个接口要请求访问,岂不是多出了很多的重复代码,这一点并不符合现在Android的现状,所以需要封装OKHttp,通过架构或者框架来完成这一步,前期虽然麻烦一些,但是你一旦用习惯了,就停不下来了,接下来我尽量用人话来讲述这个搭建过程。
为了让你有一个清晰的思路,这里创建一个模块,里面搭建MVP框架。
鼠标右键你的项目名,选择Module
接下来在AndroidManifest.xml文件中配置
现在你可以运行一下,看你的项目有没有问题,早出现问题早解决。
现在框架已经搭好了,不过页面布局还没有写好的,所以要写一下页面了。
⑤ 编辑布局文件activity_main.xml
背景图
这样你的布局文件应该就没有报错的红线了。
然后看到MainActivity.java中的这个TextView报错,因为布局文件中已经去掉了这个TextView。
删除即可
然后再绑定布局中控件
@BindView(R.id.tv_info)
TextView tvInfo;//天气状况
@BindView(R.id.tv_temperature)
TextView tvTemperature;//温度
@BindView(R.id.tv_low_height)
TextView tvLowHeight;//最高温和最低温
@BindView(R.id.tv_city)
TextView tvCity;//城市
@BindView(R.id.tv_old_time)
TextView tvOldTime;//最近更新时间
⑥ 天气查询(使用MVPActivity实现数据请求与数据渲染显示)
接下来进行使用MVP框架数据请求,删除getTodayWeather()方法。修改后的MainActivity代码如下所示
package com.llw.goodweather;
import android.Manifest;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.llw.goodweather.bean.TodayResponse;
import com.llw.goodweather.contract.WeatherContract;
import com.llw.goodweather.utils.ToastUtils;
import com.llw.mvplibrary.mvp.MvpActivity;
import com.tbruyelle.rxpermissions2.RxPermissions;
import java.io.IOException;
import butterknife.BindView;
import butterknife.ButterKnife;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import retrofit2.Response;
public class MainActivity extends MvpActivity implements WeatherContract.IWeatherView {
@BindView(R.id.tv_info)
TextView tvInfo;//天气状况
@BindView(R.id.tv_temperature)
TextView tvTemperature;//温度
@BindView(R.id.tv_low_height)
TextView tvLowHeight;//最高温和最低温
@BindView(R.id.tv_city)
TextView tvCity;//城市
@BindView(R.id.tv_old_time)
TextView tvOldTime;//最近更新时间
private RxPermissions rxPermissions;//权限请求框架
//定位器
public LocationClient mLocationClient = null;
private MyLocationListener myListener = new MyLocationListener();
//数据初始化 主线程,onCreate方法可以删除了,把里面的代码移动这个initData下面
@Override
public void initData(Bundle savedInstanceState) {
//因为这个框架里面已经放入了绑定,所以这行代码可以注释掉了。
//ButterKnife.bind(this);
rxPermissions = new RxPermissions(this);//实例化这个权限请求框架,否则会报错
permissionVersion();//权限判断
}
//绑定布局文件
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
//绑定Presenter ,这里不绑定会报错
@Override
protected WeatherContract.WeatherPresenter createPresent() {
return new WeatherContract.WeatherPresenter();
}
//权限判断
private void permissionVersion() {
if (Build.VERSION.SDK_INT >= 23) {//6.0或6.0以上
//动态权限申请
permissionsRequest();
} else {//6.0以下
//发现只要权限在AndroidManifest.xml中注册过,均会认为该权限granted 提示一下即可
ToastUtils.showShortToast(this, "你的版本在Android6.0以下,不需要动态申请权限。");
}
}
//动态权限申请
private void permissionsRequest() {//使用这个框架需要制定JDK版本,建议用1.8
rxPermissions.request(Manifest.permission.ACCESS_FINE_LOCATION)
.subscribe(granted -> {
if (granted) {//申请成功
//得到权限之后开始定位
startLocation();
} else {//申请失败
ToastUtils.showShortToast(this, "权限未开启");
}
});
}
//定位
private void startLocation() {
//声明LocationClient类
mLocationClient = new LocationClient(this);
//注册监听函数
mLocationClient.registerLocationListener(myListener);
LocationClientOption option = new LocationClientOption();
//如果开发者需要获得当前点的地址信息,此处必须为true
option.setIsNeedAddress(true);
//可选,设置是否需要最新版本的地址信息。默认不需要,即参数为false
option.setNeedNewVersionRgc(true);
//mLocationClient为第二步初始化过的LocationClient对象
//需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
mLocationClient.setLocOption(option);
//启动定位
mLocationClient.start();
}
private class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
//获取区/县
String district = location.getDistrict();
//获取今天的天气数据
mPresent.todayWeather(context,district);
}
}
//查询当天天气,请求成功后的数据返回
@Override
public void getTodayWeatherResult(Response response) {
//数据返回后关闭定位
mLocationClient.stop();
if (response.body().getHeWeather6().get(0).getBasic() != null) {//得到数据不为空则进行数据显示
//数据渲染显示出来
tvTemperature.setText(response.body().getHeWeather6().get(0).getNow().getTmp());//温度
tvCity.setText(response.body().getHeWeather6().get(0).getBasic().getLocation());//城市
tvInfo.setText(response.body().getHeWeather6().get(0).getNow().getCond_txt());//天气状况
tvOldTime.setText("上次更新时间:" + response.body().getHeWeather6().get(0).getUpdate().getLoc());
} else {
ToastUtils.showShortToast(context, response.body().getHeWeather6().get(0).getStatus());
}
}
//数据请求失败返回
@Override
public void getDataFailed() {
ToastUtils.showShortToast(context,"网络异常");//这里的context是框架中封装好的,等同于this
}
}
写完之后就可以直接运行了,运行效果图如下:
可以看到,已经得到天气数据了,只不过美中不足,上面的状态栏是原生的颜色,原谅绿,这个颜色不吉利啊。我们换一下。这个时候就可以用到透明状态栏,这种东西了,在utils包下新建一个StatusBarUtil工具类
工具类代码如下:
package com.llw.goodweather.utils;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.readystatesoftware.systembartint.SystemBarTintManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class StatusBarUtil {
@TargetApi(19)
public static void transparencyBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window window = activity.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
public static void setStatusBarColor(Activity activity, int colorId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(activity.getResources().getColor(colorId));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//使用SystemBarTint库使4.4版本状态栏变色,需要先将状态栏设置为透明
transparencyBar(activity);
SystemBarTintManager tintManager = new SystemBarTintManager(activity);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintResource(colorId);
}
}
public static int StatusBarLightMode(Activity activity) {
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (MIUISetStatusBarLightMode(activity, true)) {
result = 1;
} else if (FlymeSetStatusBarLightMode(activity.getWindow(), true)) {
result = 2;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
result = 3;
}
}
return result;
}
public static void StatusBarLightMode(Activity activity, int type) {
if (type == 1) {
MIUISetStatusBarLightMode(activity, true);
} else if (type == 2) {
FlymeSetStatusBarLightMode(activity.getWindow(), true);
} else if (type == 3) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
}
public static void StatusBarDarkMode(Activity activity, int type) {
if (type == 1) {
MIUISetStatusBarLightMode(activity, false);
} else if (type == 2) {
FlymeSetStatusBarLightMode(activity.getWindow(), false);
} else if (type == 3) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
public static boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
boolean result = false;
if (window != null) {
try {
WindowManager.LayoutParams lp = window.getAttributes();
Field darkFlag = WindowManager.LayoutParams.class
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class
.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (dark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
result = true;
} catch (Exception e) {
}
}
return result;
}
public static boolean MIUISetStatusBarLightMode(Activity activity, boolean dark) {
boolean result = false;
Window window = activity.getWindow();
if (window != null) {
Class clazz = window.getClass();
try {
int darkModeFlag = 0;
Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
if (dark) {
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
} else {
extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
}
result = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
if (dark) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
} catch (Exception e) {
}
}
return result;
}
}
接下来,在MainActivity.java中调用即可
StatusBarUtil.transparencyBar(context);//透明状态栏
然后再运行一下
不管怎么说,都比原谅绿好看。
现在查询当天的天气是可以了,但是都说是天气预报了,当然也要有啊,否则不就是骗人了吗?OK
下一篇:Android 天气APP(五)天气预报、生活指数的数据请求与渲染
作者:初学者-Study
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341