PhaseTwo(Android)
okgo
okhttp的封装 简易版Okhttp
这里继承了上一个项目中的BaseActivity,如果不明白的点下面的链接,并打开PhaseTwo(Android)
上一期的Java-Android.
package com.bawei.zhuangao2.day3;
import android.Manifest;
import android.annotation.SuppressLint;
import android.graphics.BitmapFactory;
import android.view.View;
import android.widget.ImageView;
import com.bawei.zhuangao2.R;
import com.bawei.zhuangao2.day1.HeadInterceptor;
import com.bawei.zhuangao2.day2.base.BaseActivity;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.PermissionUtils;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.cache.CacheMode;
import com.lzy.okgo.callback.FileCallback;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Response;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
//一样继承于BaseActivity
public class OkGoActivity extends BaseActivity {
//用于下载图片展示
private ImageView coverIv;
/**
* 绑定主要视图
* @return
*/
@Override
public int bandLayout() {
return R.layout.activity_okhttp;
}
/**
* 初始化控件 并设置点击事件
*/
@Override
public void initView() {
//获取隐私权限(这里隐私权限指的是:手机联系人,读写SD卡,手机信息等等)
//这里获取了写入SD卡的权限
PermissionUtils.permission(Manifest.permission.WRITE_EXTERNAL_STORAGE).request();
findViewById(R.id.btn1).setOnClickListener(this);
findViewById(R.id.btn2).setOnClickListener(this);
findViewById(R.id.btn3).setOnClickListener(this);
findViewById(R.id.btn4).setOnClickListener(this);
findViewById(R.id.btn5).setOnClickListener(this);
findViewById(R.id.btn6).setOnClickListener(this);
coverIv = findViewById(R.id.image);
}
@Override
public void initData() {
}
/**
* 点击事件
* @param v
*/
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
//Get方式获取
OkGo.<String>get("https://gank.io/api/v2/banners").execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
//对Response 做了解析
//这里还是异步线程
LogUtils.d(response.body());
}
@Override
public void onCacheSuccess(Response<String> response) {
super.onCacheSuccess(response);
LogUtils.d("onCacheSuccess" + response.body());
}
});
break;
case R.id.btn2:
//Post Json 通过upJson("")提交代码
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("username", "1234567");
jsonObject.put("pwd", "123456");
jsonObject.put("sex", "1");
jsonObject.put("birthday", "2000-9-9");
} catch (JSONException e) {
e.printStackTrace();
}
OkGo.<String>post("http://39.98.153.96:8082/api/WeekTest/register")
.upJson(jsonObject.toString()).execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
//Response 对做了解析
//这里还是异步线程
LogUtils.d(response.body());
}
});
break;
case R.id.btn3:
//Post From
//username=1903001&pwd=123456
OkGo.<String>post("http://39.98.153.96:8082/api/WeekTest/login?username=1903001&pwd=123456")
.params("username", "1903001")
.params("pwd", "123456")
.execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
//Response 对做了解析
//这里还是异步线程
LogUtils.d(response.body());
}
});
break;
case R.id.btn4:
//下载
OkGo.<File>get("https://pic.downk.cc/item/5e7b64fd504f4bcb040fae8f.jpg").execute(new FileCallback() {
@Override
public void onSuccess(final Response<File> response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
LogUtils.d(response.body().getPath());
coverIv.setImageBitmap(BitmapFactory.decodeFile(response.body().getPath()));
}
});
}
});
break;
case R.id.btn5:
break;
case R.id.btn6:
//文件上传
File file = new File("/storage/emulated/0/download/1382400000b859e1c2339");
coverIv.setImageBitmap(BitmapFactory.decodeFile(file.getPath()));
OkGo.<String>post("http://117.51.155.210/hfs/")
//发送格式为file
.params("file",file)
//分段发送
.isMultipart(true)
.execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
LogUtils.d(response.body());
}
});
break;
}
}
}
Glide工具
认识Glide
Glide是一个图片加载框架,功能强大,一般用于一些视图显示图片,从url中加载图片等等,也可以进行裁剪图片,达到视觉美观
Glide方法类
/**
* 单例 双重校验 双重锁
*/
public class ImageManger {
public void showImage(String url, ImageView view){
Glide.with(Utils.getApp()).load(url)
//关闭缓存
.skipMemoryCache(true)
//关闭磁盘缓存
.diskCacheStrategy(DiskCacheStrategy.NONE)
//加载过程显示
.placeholder(R.mipmap.ic_launcher)
//加载失败显示
.error(R.mipmap.ic_launcher)
.into(view);
}
public void showR(String url, ImageView view,int radius){
Glide.with(Utils.getApp()).load(url)
.transform(new RoundedCorners(radius))
//加载过程显示
.placeholder(R.mipmap.ic_launcher)
//加载失败显示
.error(R.mipmap.ic_launcher)
.into(view);
}
public void showC(String url, ImageView view){
Glide.with(Utils.getApp()).load(url)
//圆形
.circleCrop()
.into(view);
}
//多线程可见
private static volatile ImageManger imageManger;
//饿汉式单例
public static ImageManger getInstance(){
if (imageManger==null){
//这里上锁
synchronized (ImageManger.class){
if (imageManger==null){
imageManger=new ImageManger();
}
}
}
return imageManger;
}
}
Activity类
public class GlideActivity extends BaseActivity {
private android.widget.ImageView actGlideIv01;
private android.widget.ImageView actGlideIv02;
private android.widget.ImageView actGlideIv03;
//初始化主视图
@Override
public int bandLayout() {
return R.layout.activity_glide;
}
//初始化控件
@Override
public void initView() {
actGlideIv01 = findViewById(R.id.act_glide_iv_01);
actGlideIv02 = findViewById(R.id.act_glide_iv_02);
actGlideIv03 = findViewById(R.id.act_glide_iv_03);
}
//加载数据(显示图片)
@Override
public void initData() {
//实例化调用方法 完成Glide加载
ImageManger imageManger = new ImageManger();
imageManger.showImage("https://pic.downk.cc/item/5e7b64fd504f4bcb040fae8f.jpg",actGlideIv01);
imageManger.showC("https://pic.downk.cc/item/5e7b64fd504f4bcb040fae8f.jpg",actGlideIv02);
imageManger.showR("https://pic.downk.cc/item/5e7b64fd504f4bcb040fae8f.jpg",actGlideIv03,50);
}
}
MVP
在MVC中,View层是可直接调用Model层的,当发生一些特殊的情况时,无法及时更换网络请求
而MVP中则可以,MVP的主要目的是解耦,P层用于调用M层,V层则用来访问P层
内容较多:可以参考Github网站 > MVP整合框架
MVP分为:
(数据访问层)
Model层: 用于进行数据请求,一般用P层调用其中方法
(连接层)
Presenter层: 中文翻译为"主持人",一般用于连接M层和V层, V层调用P层, P层再调用M层
(视图层)
View层:用于视图展示, 继承回调接口等 调用P层中方法获取数据
目录
Base_lib
一个library组件 其中的抽象类用于被继承, 用于自定义 更加的方便写MVP
基础model层
(接口)
public
interface IModel {
void destroy();
}
(抽象实现类)
//销毁方法
public abstract
class BaseModel implements IModel {
@Override
public void destroy() {
}
}
基础View层
(IActivity 基础activity接口)
public
interface IActivity {
//用于初始化视图
void initView();
//用于加载数据
void initData();
//用于绑定视图时使用(获取视图)
int bindLayout();
}
(IView 基础view层接口)
public
interface IView {
//用于显示进度条
void showLoading();
//用于隐藏进度条
void hideLoading();
//用于便捷Toast信息
void showToast(String msg);
}
(BaseActivity 基础activity抽象实现类)
/**
* 和正常Activity一样继承AppCompatActivity 需要实现activity的接口 和 视图层的接口
*/
public abstract
class BaseActivity extends AppCompatActivity implements IActivity,IView {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(bindLayout()); //这里调用获取视图方法 用于设置主视图
//初始化视图
initView();
//初始化数据
initData();
}
/**
* Toast信息
* @param msg 需要Toast的信息
*/
@Override
public void showToast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
(IFragment 基础fragment接口)
public
interface IFragment extends IActivity {
//方便Fragment 初始化组件
<T extends View> T findViewById(@IdRes int id);
}
(BaseFragment 基础fragment抽象实现类)
public abstract
class BaseFragment extends Fragment implements IView,IFragment {
private View view;
/**
* 创建视图时调用
* @param inflater
* @param container
* @param savedInstanceState
* @return
*/
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//这里绑定主视图
view = inflater.inflate(bindLayout(),container,false);
//返回主视图
return view;
}
/**
* 创建视图后调用
* @param view
* @param savedInstanceState
*/
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//初始化视图
initView();
//初始化数据
initData();
}
/**
* 实现findViewById方法
* @param id
* @param <T>
* @return
*/
@Override
public <T extends View> T findViewById(int id) {
return view.findViewById(id);
}
}
基础Presenter层
(IPresenter 基础 P层接口)
public
interface IPresenter{
//销毁方法
void destroy();
}
(IPresenter基础 P层抽象实现类)
//创建泛型 一个转型V层,另一个M层
public abstract
class BasePresenter<V extends IView,M extends IModel> implements IPresenter {
//创建两个继承类可调用的变量
protected V view;
protected M model;
//构造方法
public BasePresenter(V view, M model) {
this.view = view;
this.model = model;
}
//销毁方法
@Override
public void destroy() {
if (model!=null){
model.destroy();
model = null;
}
}
}
app主要模块
Api接口
//Api接口 用于编写Retrofit调用的方法
public
interface Api {
/**
* Get方式获取数据
* @param url 用于加载的url的后缀(主要部分在Utils层中)
* @return
*/
@GET
Observable<FoodEntity> getFood(@Url String url);
/**
* 另外一种写法 可以把url后缀写为固定值 参数自己传
* @param page page参数 会自动给到url中作为参数
* @return
*/
@GET("dish_list.php?stage_id=1&limit=20")
Observable<FoodEntity> getFood(@Query("page")int page);
}
Utils层
(HttpFoodUtils单例类 初始化retrofit)
/**
* 网络请求数据 单例类
*/
public
class HttpFoodUtils {
private static HttpFoodUtils utils;
private Retrofit retrofit;
/**
* 饿汉式单例
* @return
*/
public static HttpFoodUtils getInstance() {
if (utils==null){
utils = new HttpFoodUtils();
}
return utils;
}
//初始化 类似单例
public Retrofit getRetrofit() {
if (retrofit==null){
retrofit = new Retrofit.Builder()
//这里填写主要url
.baseUrl("http://www.qubaobei.com/ios/cf/")
//添加Okhttp拦截器 并设置超时时间
.client(new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.readTimeout(2, TimeUnit.MINUTES)
.connectTimeout(2,TimeUnit.MINUTES)
.writeTimeout(2,TimeUnit.MINUTES)
.build())
//添加解析工厂和回调工厂
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//创建
.build();
}
//返回
return retrofit;
}
}
IContract
public
interface IContract {
//获取数据的视图接口
interface IFoodView extends IView{
/**
* 显示数据
* @param list 展示的数据集合
*/
void showFood(List<FoodEntity.DataBean> list);
}
//获取数据的M层接口
interface IFoodModel extends IModel{
/**
* 获取数据
* @param url 后缀链接
* @param observer 观察者
*/
void getFood(String url,Observer<FoodEntity> observer);
}
}
M层
获取数据 网络请求的方法 调用Retrofit中的单例方法 实现API.class中的方法
public
class FoodModel extends BaseModel implements IContract.IFoodModel {
//获取数据 网络请求的方法 调用Retrofit中的单例方法 实现API.class中的方法 并回调观察者
@Override
public void getFood(String url,Observer<FoodEntity> observer) {
HttpFoodUtils.getInstance()
.getRetrofit()
.create(Api.class)
.getFood(url)
//RxJava框架
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(observer);
}
@Override
public void destroy() {
//销毁方法
}
}
P层
/**
* P层
*/
public
class FoodPresenter extends BasePresenter<IContract.IFoodView, IContract.IFoodModel> {
private Disposable disposable;
public FoodPresenter(IContract.IFoodView view, IContract.IFoodModel model) {
super(view, model);
}
public void getFood(String url){
model.getFood(url, new Observer<FoodEntity>() {
@Override
public void onSubscribe(Disposable d) {
disposable = d; //设为全局
}
@Override
public void onNext(FoodEntity foodEntity) {
view.showFood(foodEntity.getData());
}
@Override
public void onError( Throwable e) {
ToastUtils.showShort(e.getMessage().toString());
disposable.dispose(); //遇到错误后 杀死d 断开M层和V层的连接 防止内存泄漏
}
@Override
public void onComplete() {
disposable.dispose(); //方法执行完毕后 断开连接
}
});
}
}
V层
主视图 用于显示数据 调用P层中的方法获取数据
public class MainActivity extends BaseActivity implements IContract.IFoodView, OnRefreshLoadMoreListener, OnRefreshListener, OnItemClickListener, OnItemLongClickListener {
//Recycler的适配器(用于适配数据)
private RecyclerAdapter recyclerAdapter;
//RecyclerView展示数据控件
private androidx.recyclerview.widget.RecyclerView mainRv;
//P层
private FoodPresenter foodPresenter;
//页码和数量(用于分页 改变Url中的参数)
private int page = 1,count = 20;
//刷新控件
private com.scwang.smart.refresh.layout.SmartRefreshLayout mainRefresh;
//是否用于刷新
private boolean isRefresh = false;
//整合的数据
private List<FoodEntity.DataBean> dataBeans;
/**
* 初始化控件和一些全局变量对象
*/
@Override
public void initView() {
foodPresenter = new FoodPresenter(this,new FoodModel());
mainRv = findViewById(R.id.main_rv);
mainRv.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));
mainRefresh = findViewById(R.id.main_refresh);
mainRefresh.setOnRefreshListener(this);
mainRefresh.setOnLoadMoreListener(this);
}
/**
* 开始使用P层的getFood方法获取数据
*/
@Override
public void initData() {
foodPresenter.getFood("dish_list.php?stage_id=1&limit="+count+"&page="+page);
}
//绑定主视图(必写)
@Override
public int bindLayout() {
return R.layout.activity_main;
}
/**
* 由于没写进度条 所以空闲
*/
@Override
public void showLoading() {
}
/**
* 由于没写进度条 所以空闲
*/
@Override
public void hideLoading() {
}
/**
* 显示数据(回调方法)
* @param list 展示的数据集合
*/
@Override
public void showFood(List<FoodEntity.DataBean> list) {
//调用初始化适配器方法
initAdapter(list);
}
/**
* 上拉加载更多
* @param refreshLayout
*/
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
//把是否刷新改为否
isRefresh = false;
//页码+1
++page;
//并获取数据
foodPresenter.getFood("dish_list.php?stage_id=1&limit="+count+"&page="+page);
}
/**
* 下拉刷新
* @param refreshLayout
*/
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
//把是否刷新改为是
isRefresh = true;
//页码=1(重新开头)
page = 1;
//获取数据
foodPresenter.getFood("dish_list.php?stage_id=1&limit="+count+"&page="+page);
}
/**
* 初始化适配器
* @param list 回调回来的数据
*/
private void initAdapter(List<FoodEntity.DataBean> list) {
//判断适配器是否为空(是否是刚运行加载的数据)
if (recyclerAdapter==null){
//是的话就初始化 并设置点击事件和适配
recyclerAdapter = new RecyclerAdapter(list);
recyclerAdapter.setOnItemClickListener(this);
recyclerAdapter.setOnItemLongClickListener(this);
mainRv.setAdapter(recyclerAdapter);
}else {
//不是的话 判断是否为刷新
if (isRefresh) {
//是刷新就清空适配器
recyclerAdapter.getData().clear();
}
//然后正常添加适配数据 并刷新数据(不管是不是刷新 都会执行)
recyclerAdapter.getData().addAll(list);
recyclerAdapter.notifyDataSetChanged();
}
//最后将整合全局数据 改为 设配器其中的数据
dataBeans = recyclerAdapter.getData();
//结束刷新加载动画
mainRefresh.finishRefresh();
mainRefresh.finishLoadMore();
}
/**
* 条目点击事件
* @param adapter
* @param view
* @param position
*/
@Override
public void onItemClick(@NonNull @NotNull BaseQuickAdapter<?, ?> adapter, @NonNull @NotNull View view, int position) {
//使用ARouter跳转并传值(跳转到详情页)需要在Application中初始化 “ARouter.init(this);”
ARouter.getInstance().build("/test/details")
.withSerializable("object",dataBeans.get(position))
.navigation();
}
/**
* 条目长按点击事件
* @param adapter
* @param view
* @param position
* @return
*/
@Override
public boolean onItemLongClick(@NonNull @NotNull BaseQuickAdapter adapter, @NonNull @NotNull View view, int position) {
dataBeans.remove(position);
recyclerAdapter.notifyItemRemoved(position);
showToast("删除成功");
return true;
}
}
到此MVP结束
补间动画
作用于View控件的动画
补间动画系统自带 已经封装好的动画类,可以直接使用简单方便
intent使用(不是简单跳转页面)
可以拨号 发消息 跳转相机 从图库选择一张图片等等
权限需要自己添加:拨号权限,读取联系人权限,相机拍照权限等等
背景模糊
导入以下依赖
compile 'jp.wasabeef:blurry:3.0.0'
轮播图banner
banner是一个已经封装好的轮播图类,可以直接使用简单方便
侧拉框
一个可以从侧边划出来的视图
需要导入Moudle “lib_slide”
百度网盘链接:lib_slide 提取码:1233
手机验证码(EditText自动跳转)
//文字监听
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (before > count){
}else{
//设置本身失去焦点
editText.clearFocus();
if (nextEditText >= list.size()){
return;
}
list.get(nextEditText).requestFocus();
}
}
//键盘按键监听
editText.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
//判断是否为删除键
if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_DEL){
if (nowEditText == 0){
//如果删除到最后一个了 就清空
editText.setText("");
//并且还是获取自身焦点(没有什么重要)
list.get(nowEditText).requestFocus();
return false;
}
if (editText.getText().toString().isEmpty() && !list.get(lastEditText).getText().toString().isEmpty()){
//本身失去焦点
editText.clearFocus();
//上一个清空
list.get(lastEditText).setText("");
//上一个获取焦点
list.get(lastEditText).requestFocus();
}
}
return false;
}
});
注解传值规范
@IntDef({AuthCodeView.FOUR_DIGIT,AuthCodeView.SIX_DIGIT})
@Retention(RetentionPolicy.SOURCE)
public @interface InputSize {
}
将以上的注解放到属性上,此属性只能传入AuthCodeView.FOUR_DIGIT,AuthCodeView.SIX_DIGIT 两个参数