此为课堂笔记!!!
用的是banner
GitHub地址
国际惯例先上图:
使用步骤:
Step1:
1.在build.gradle(Module:app)里引入依赖:implementation ‘com.youth.banner:banner:2.0.1’
2.在build.gradle(Module:app)的android控件里添加支持java8,记得点击右上角的Sync Now同步
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Step2:写一个适配器:
1.准备工作:
ps:因为用到 RecyclerView 和 Glide ,所以需要引入依赖:
//recyclerview 列表
implementation ‘androidx.recyclerview:recyclerview:1.1.0’
//glide 图片加载
implementation ‘com.github.bumptech.glide:glide:4.11.0’
annotationProcessor ‘com.github.bumptech.glide:compiler:4.11.0’
2.正式代码:
//Step2: 继承BannerAdapter后并实现BannerViewHolder和onBindView方法,并需要构造器
//ps:BannerBean 是一个bean,有存放图片名称的属性,用来拼接请求服务器图片的路径,自行建一个bean存放图片路径
public class ImageAdapter extends BannerAdapter<BannerBean,ImageAdapter.BannerViewHolder> {
private Context context;
public ImageAdapter(List<BannerBean> datas , Context context) {
super(datas);
this.context=context;
}
/*创建ViewHolder,可以用viewType这个字段来区分不同的ViewHolder*/
@Override
public BannerViewHolder onCreateHolder(ViewGroup parent, int viewType) {
ImageView imageView =new ImageView(parent.getContext());
//注意,必须设置为match_parent,这个是viewpager2强制要求的
imageView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
return new BannerViewHolder(imageView);
}
/*绑定数据*/
@Override
public void onBindView(BannerViewHolder holder, BannerBean data, int position, int size) {
//这是请求服务端图片的路径,返回的是图片流
String strImagePath = ServiceUrls.getMainPageMethodUrl("getBannerPicture") + "?pictureName=" + data.getBannerPicture();
//用Glide请求加载图片,
Glide.with(context)
.load(strImagePath)
.into(holder.imageView);
}
//Step1
class BannerViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
public BannerViewHolder(@NonNull ImageView view) {
super(view);
this.imageView=view;
}
}
}
Step3:在需要轮播的布局文件中添加Banner:
<com.youth.banner.Banner
android:id="@+id/banner_home_header"
android:layout_width="match_parent"
android:layout_height="240dp" />
Step4:Banner具体方法的调用:
1.准备工作:
ps:因为这里用到了网络请求 和 其工具,还有 fastjson,所以需要引入以下:
引入依赖:
//==网络请求 需要设置网络权限
implementation ‘com.squareup.okhttp3:okhttp:4.4.0’//网络请求
implementation ‘com.squareup.okhttp3:logging-interceptor:4.4.0’//发送网络请求和返回数据的相关日志
//fastjson
implementation ‘com.alibaba:fastjson:1.2.68’
设置开启联网权限:在AndroidManifest.xml里的manufest里添加子控件,代码如下:
<!--添加时是此处代码:允许程序打开网络套接字-->
<uses-permission android:name="android.permission.INTERNET" />
用到的工具类(老师的):该工具类是请求服务器的方法,若自己有,则不需要:
package com.gx.banner;
import android.util.Log;
import androidx.annotation.NonNull;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
/**
* create by qzlysxj
* Fix bu qzlysxj on 2020-2-26
* <p>
* 便于使用okhttp3的工具类
*/
public class OkHttpTool {
//日志标志
private static String TAG = "OkHttpTool";
//OkHttpClient类
private static final OkHttpClient myOkHttpClient;
static {
//========日志拦截器=========
//Log拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(@NonNull String message) {
Log.i(TAG, message);
}
});
//设置日志显示级别
HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.BODY;
loggingInterceptor.setLevel(level);
//========cookie处理--让服务端记住app
//这里是设置cookie的,但是并没有做持久化处理;只是把cookie保存在内存中
CookieJar cookieJar=new CookieJar() {
private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
//保存cookie
@Override
public void saveFromResponse(@NonNull HttpUrl url, @NonNull List<Cookie> cookies) {
cookieStore.put(url.host(), cookies);
}
//获取cookie
@Override
public List<Cookie> loadForRequest(@NonNull HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
}
};
//创建OkHttpClient
myOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)//连接超时
.writeTimeout(60, TimeUnit.SECONDS)//写入超时
.readTimeout(60, TimeUnit.SECONDS)//读取超时
.addInterceptor(loggingInterceptor)//添加日志处理拦截器
.cookieJar(cookieJar)
.build();
}
//================对外方法=====================
/**
* Get 请求
* @param url{String} 请求地址
* @param parameters{Map<String, Object>} 请求参数
* @param responseCallback{ResponseCallback} 请求回调
*/
@SuppressWarnings("unused")
public static void httpGet(String url, Map<String, Object> parameters, ResponseCallback responseCallback) {
Request request = createGetRequest(url, parameters);
doRequest(request, responseCallback);
}
/**
* POST 请求
* @param url{String} 请求地址
* @param parameters{Map<String, Object>} 请求参数
* @param responseCallback{ResponseCallback} 请求回调
*/
public static void httpPost(String url, Map<String, Object> parameters, ResponseCallback responseCallback) {
Request request = createPostRequest(url, parameters);
doRequest(request, responseCallback);
}
/**
* POST 请求 JSON格式参数
* @param url{String} 请求地址
* @param json{String} JSON格式参数
* @param responseCallback{ResponseCallback} 请求回调
*/
@SuppressWarnings("unused")
public static void httpPostJson(String url, String json, ResponseCallback responseCallback) {
Request request = createPostRequestJson(url, json);
doRequest(request, responseCallback);
}
/**
* POST 请求 文件上传
* @param url{String} 请求地址
* @param parameters{Map<String, Object>} 请求参数
* @param files{Map<String, File>} 上传的文件列表
* @param responseCallback{ResponseCallback} 请求回调
*/
@SuppressWarnings("unused")
public static void httpPostWithFile(String url, Map<String, Object> parameters, Map<String, File> files, ResponseCallback responseCallback) {
Request request = createPostRequestWithFile(url, parameters, files);
doRequest(request, responseCallback);
}
/**
* POST 请求 文件上传 byte数组
* @param url{String} 请求地址
* @param parameters{Map<String, Object>} 请求参数
* @param files{Map<String, byte[]>}上传的文件列表
* @param responseCallback{ResponseCallback} 请求回调
*/
@SuppressWarnings("unused")
public static void httpPostWithFileByte(String url, Map<String, Object> parameters, Map<String, byte[]> files, ResponseCallback responseCallback) {
Request request = createPostRequestWithFileByte(url, parameters, files);
doRequest(request, responseCallback);
}
//=====回调接口======
public interface ResponseCallback {
void onResponse(boolean isSuccess, int responseCode, String response, Exception exception);
}
//===========私有方法===============
//====构建请求====
//构建 Get请求
private static Request createGetRequest(String url, Map<String, Object> parameters) {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(url);
if (url.indexOf('?') <= -1) {
//未拼接参数
urlBuilder.append("?");
}
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
urlBuilder.append("&");
urlBuilder.append(entry.getKey());
urlBuilder.append("=");
urlBuilder.append(entry.getValue().toString());
}
return getBaseRequest().url(urlBuilder.toString()).build();
}
//构建 POST 请求
private static Request createPostRequest(String url, Map<String, Object> parameters) {
@SuppressWarnings("all")
FormBody.Builder builder = new FormBody.Builder(Charset.forName("UTF-8"));
if (parameters != null) {
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
builder.add(entry.getKey(), entry.getValue().toString());
}
}
FormBody formBody = builder.build();
return getBaseRequest().url(url).post(formBody).build();
}
//构建 POST JSON格式参数请求
private static Request createPostRequestJson(String url, String json) {
MediaType mediaType = MediaType.parse("application/json;charset=utf-8");
RequestBody body = RequestBody.create(json,mediaType);
return getBaseRequest().url(url).post(body).build();
}
//构建 POST带文件的 请求
private static Request createPostRequestWithFile(String url, Map<String, Object> parameters, Map<String, File> files) {
// form 表单形式上传
MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
if (files != null) {
for (Map.Entry<String, File> fileEntry : files.entrySet()) {
File file = fileEntry.getValue();
if (file != null) {
// MediaType.parse() 里面是上传的文件类型。
RequestBody body = RequestBody.create(file,MediaType.parse("application/octet-stream"));
String filename = file.getName();
// 参数分别为, 请求key ,文件名称 , RequestBody
requestBody.addFormDataPart(fileEntry.getKey(), filename, body);
}
}
}
if (parameters != null) {
// map 里面是请求中所需要的 key 和 value
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
String key = entry.getKey();
String value = entry.getValue().toString();
requestBody.addFormDataPart(key, value);
}
}
return getBaseRequest().url(url).post(requestBody.build()).build();
}
//构建 POST带文件的 请求
private static Request createPostRequestWithFileByte(String url, Map<String, Object> parameters, Map<String, byte[]> files) {
// form 表单形式上传
MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
if (files != null) {
for (Map.Entry<String, byte[]> fileEntry : files.entrySet()) {
byte[] file = fileEntry.getValue();
if (file != null) {
// MediaType.parse() 里面是上传的文件类型。
RequestBody body = RequestBody.create(file,MediaType.parse("application/octet-stream"));
// 参数分别为, 请求key ,文件名称 , RequestBody
requestBody.addFormDataPart(fileEntry.getKey(), fileEntry.getKey(), body);
}
}
}
if (parameters != null) {
// map 里面是请求中所需要的 key 和 value
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
String key = entry.getKey();
String value = entry.getValue().toString();
requestBody.addFormDataPart(key, value);
}
}
return getBaseRequest().url(url).post(requestBody.build()).build();
}
//===实际进行请求的方法
private static void doRequest(final Request request, final ResponseCallback responseCallback) {
//使用okhttp3的异步请求
myOkHttpClient.newCall(request).enqueue(new Callback() {
//失败回调
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
//回调
responseCallback.onResponse(false, -1, null, e);
//用于输出错误调试信息
if (e.getMessage()!=null){
Log.e(TAG, e.getMessage());
}
}
//成功回调
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
int responseCode = response.code();//获取响应码
ResponseBody responseBody = response.body();//获取 ResponseBody
if (response.isSuccessful() && responseBody != null) {
String strResponse = responseBody.string();
//回调
responseCallback.onResponse(true, responseCode, strResponse, null);
} else {
//回调
responseCallback.onResponse(false, responseCode, null, null);
}
}
});
}
//获取请求 指定client为Android
private static Request.Builder getBaseRequest() {
Request.Builder builder = new Request.Builder();
builder.addHeader("client", "Android");
return builder;
}
}
//.addInterceptor(new Interceptor() {
// @Override
// public Response intercept(@NonNull Chain chain) throws IOException {
// Request request = chain.request().newBuilder()
// .addHeader("Connection", "close").build();
// return chain.proceed(request);
// }
//})
/*以前自己写的日志拦截器*/
//添加日志处理拦截器
//.addInterceptor(new Interceptor() {
// @Override
// public Response intercept(@NonNull Chain chain) throws IOException {
// Request request = chain.request();
// long startTime = System.currentTimeMillis();
// Response response = chain.proceed(chain.request());
// long endTime = System.currentTimeMillis();
// long duration = endTime - startTime;
// MediaType mediaType = response.body().contentType();
// String content = response.body().string();
// Log.d(TAG, "\n");
// Log.d(TAG, "----------Start----------------");
// Log.d(TAG, "| " + request.toString());
// String method = request.method();
// if ("POST".equals(method)) {
// StringBuilder sb = new StringBuilder();
// if (request.body() instanceof FormBody) {
// FormBody body = (FormBody) request.body();
// for (int i = 0; i < body.size(); i++) {
// sb.append(body.encodedName(i) + "=" + body.encodedValue(i) + ",");
// }
// if (sb.length() > 0) {
// //在参数不为空的情况下处理最后的 “,”
// sb.delete(sb.length() - 1, sb.length());
// }
// Log.d(TAG, "| RequestParams:{" + sb.toString() + "}");
// }
// }
// Log.d(TAG, "| Response:" + content);
// Log.d(TAG, "----------End:" + duration + "毫秒----------");
// //由于前面的代码已经获取了响应结果,会导致后续代码无法获取到响应结果
// // 需要重新构建一个响应结果并返回
// return response.newBuilder()
// .body(ResponseBody.create(mediaType, content))
// .build();
// }
//})
2.正式代码:
public class MainActivity extends AppCompatActivity {
private Banner banner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
banner = findViewById(R.id.banner_home_header);//获取Banner控件
initView();
}
private void initView() {
//==获取服务端需要轮播的图片名称list集合数据
String url= ServiceUrls.getMainPageMethodUrl("getBannerInfo");//请求路径
OkHttpTool.httpPost(url, null, new OkHttpTool.ResponseCallback() {
@Override
public void onResponse(final boolean isSuccess, final int responseCode, final String response, Exception exception) {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
if(isSuccess && responseCode==200){
List<BannerBean> bannerBeanList= JSON.parseObject(response,new TypeReference<List<BannerBean>>(){});
//****重点在这:显示轮播(前面的代码只是获取需要轮播的图片名称集合,准备数据)
banner.setAdapter(new ImageAdapter(bannerBeanList,MainActivity.this))
.setIndicator(new CircleIndicator(MainActivity.this))//设置圆形指示器
.setIndicatorSelectedColorRes(R.color.colorPrimary)//设置被选中的指示器的颜色
.isAutoLoop(true)//自动开启轮播
.setDelayTime(2*1000)//轮播间隔
.setOnBannerListener(new OnBannerListener() {//图片点击事件
@Override
public void OnBannerClick(Object data, int position) {
Toast.makeText(MainActivity.this,"点击了图片",Toast.LENGTH_SHORT).show();
}
});
banner.start();//开启轮播
}else{
Toast.makeText(MainActivity.this,"连接服务器失败",Toast.LENGTH_SHORT).show();
}
}
});
}
});
}
}
tip:因是Android P系统限制了明文流量的网络请求,所以必须做以下工作
1.在res层右键》New》Folder》XML Resources Folder》finis
2.res层就多了个xml层,然后新建network_security_config.xml放进xml层,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!--开发中可以考虑使用-->
<!--Android API 28 关闭HTTPS服务器监测-->
<base-config cleartextTrafficPermitted="true" />
<!--实际部署后只放开自己的服务端地址-->
<!--只将本服务XXX.XXX.XXX.XXX器放开-->
<!-- <domain-config cleartextTrafficPermitted="true">-->
<!-- <domain includeSubdomains="true">XXX.XXX.XXX.XXX</domain>-->
<!-- </domain-config>-->
</network-security-config>
3.在AndroidManifest.xml添加 android:networkSecurityConfig="@xml/network_security_config"即可:
<application
android:networkSecurityConfig="@xml/network_security_config"