项目需求
在网络加载中使用网络加载框,在请求数据或者其他耗时操作的时候,显示加载框,当数据返回之后或者操作完成的时候加载框取消。
效果如下:
需求实现
使用一个开源库【Gloading】实现
项目地址链接: Gloading
1.引入依赖
//网络加载状态
api 'com.billy.android:gloading:1.1.0'
2.初始化(一般在Application里面初始化,在Activity也行)
//初始化Gloading GlobalAdapter类需要我们自己创建
Gloading.initDefault(new GlobalAdapter());
3.我们如果创建的是一个全局加载的加载框,那就创建一个基类Activity,命名为BaseActivity。
public class BaseActivity extends AppCompatActivity {
protected Gloading.Holder mHolder;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected void initGloadingState() {
if (mHolder == null) {
mHolder = Gloading.getDefault().wrap(this).withRetry(new Runnable() {
@Override
public void run() {
onLoadRetry();
}
});
}
}
//加载失败重试时使用
protected void onLoadRetry() {}
//这是可以显示特定文字的加载框,如此方法就可显示【请求登录】
public void showLogin() {
initGloadingState();
mHolder.withData("请求登录");
mHolder.showLoading();
}
public void showLoginSuccess() {
initGloadingState();
mHolder.withData("登录成功");
mHolder.showLoadSuccess();
}
public void showLoginFailed() {
initGloadingState();
mHolder.withData("登录失败\n点击重试");
mHolder.showLoadFailed();
}
//这是显示默认文字的加载框
public void showLoadingView() {
initGloadingState();
mHolder.showLoading();
}
public void showLoadingSuccessView() {
initGloadingState();
mHolder.showLoadSuccess();
}
public void showLoadingFailView() {
initGloadingState();
mHolder.showLoadFailed();
}
}
4.基类Fragment,命名为BaseFragment,和Activity里面的差不多。
open class BaseFragment : Fragment() {
private var mHolder: Gloading.Holder? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
initGloadingState()
return super.onCreateView(inflater, container, savedInstanceState)
}
protected open fun initGloadingState() {
if (mHolder == null) {
mHolder = Gloading.getDefault().wrap(requireActivity()).withRetry { onLoadRetry() }
}
}
protected open fun onLoadRetry() {}
open fun showLoadingView() {
initGloadingState()
mHolder?.showLoading()
}
open fun showLoadingSuccessView() {
initGloadingState()
mHolder?.showLoadSuccess()
}
open fun showLoadingFailView() {
initGloadingState()
mHolder?.showLoadFailed()
}
}
5.创建GlobalAdapter,这是我们初始化时需要的类
public class GlobalAdapter implements Gloading.Adapter {
@Override
public View getView(Gloading.Holder holder, View convertView, int status) {
GlobalLoadingStatusView loadingStatusView = null;
if (convertView instanceof GlobalLoadingStatusView) {
loadingStatusView = (GlobalLoadingStatusView) convertView;
}
if (loadingStatusView == null) {
loadingStatusView = new GlobalLoadingStatusView(holder.getContext(), holder.getRetryTask());
}
//这里获取传入的文字
String strMessage = holder.getData();
if (strMessage != null) {
loadingStatusView.setStatus(status, strMessage);
} else {
loadingStatusView.setStatus(status, "");
}
holder.withData("");
loadingStatusView.setMsgViewVisibility(true);
return loadingStatusView;
}
}
6.创建GlobalLoadingStatusView 类,GlobalAdapter需要此类
@SuppressLint("ViewConstructor")
public class GlobalLoadingStatusView extends RelativeLayout implements View.OnClickListener {
private final TextView mTextView;
private final Runnable mRetryTask;
private final ImageView mImageView;
public GlobalLoadingStatusView(Context context, Runnable retryTask) {
super(context);
setGravity(Gravity.CENTER_HORIZONTAL);
LayoutInflater.from(context).inflate(R.layout.view_global_loading_status, this, true);
RelativeLayout relativeLayout = findViewById(R.id.rv_gloading);
relativeLayout.getBackground().mutate().setAlpha(150);
mImageView = findViewById(R.id.image);
mTextView = findViewById(R.id.text);
this.mRetryTask = retryTask;
}
public void setMsgViewVisibility(boolean visible) {
mTextView.setVisibility(visible ? VISIBLE : GONE);
}
//这里设置文字显示,如果不传入文字就使用下面的默认文字
public void setStatus(int status, String message) {
boolean show = true;
View.OnClickListener onClickListener = null;
int image = R.drawable.loading;
String str = "";
if (status == STATUS_LOAD_SUCCESS) {
show = false;
} else if (status == STATUS_LOADING) {
str = "加载中...";
} else if (status == STATUS_LOAD_FAILED) {
str = "加载失败";
image = R.drawable.icon_failed;
Boolean networkConn = isNetworkConnected(getContext());
if (networkConn != null && !networkConn) {
str = "网络连接失败";
image = R.drawable.icon_no_wifi;
}
onClickListener = this;
} else if (status == STATUS_EMPTY_DATA) {
str = "数据为空";
image = R.drawable.icon_empty;
}
mImageView.setImageResource(image);
setOnClickListener(onClickListener);
if (message != null && !message.isEmpty()) {
mTextView.setText(message);
} else {
mTextView.setText(str);
}
setVisibility(show ? View.VISIBLE : View.GONE);
}
@Override
public void onClick(View v) {
if (mRetryTask != null) {
mRetryTask.run();
}
}
}
7.加载框视图【view_global_loading_status】
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/rv_gloading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#333333"
tools:ignore="UseCompoundDrawables">
<androidx.cardview.widget.CardView
android:layout_width="150dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
app:cardCornerRadius="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#99666666"
android:orientation="vertical">
<ImageView
android:id="@+id/image"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:layout_marginTop="40dp"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="18sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
8.用到的图片
无网络【icon_no_wifi】
加载【icon_loading】
加载失败【icon_failed】
无数据【icon_empty】
我们在加载数据的时候,需要这个加载的图片动起来,创建xml文件,命名为【loading】
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_loading"
android:fromDegrees="0.0"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:toDegrees="360.0" />
9.使用
创建一个Activity继承BaseActivity
在加载框使用中,当数据请求成功之后,加载框会消失,但是当数据请求失败的时候,加载框不会消失,就会卡在那里,但是我们有时候需要重试功能,所以在加载框失败的时候也不能简单的消失就行了,同时此时手机的返回键点击的时候会将整个Activity干掉,此时需要处理这个问题。
class LoginActivity : BaseActivity() {
private lateinit var binding: ActivityLoginBinding
private val loginViewModel: LoginModel by lazy {
ViewModelProvider(this)[LoginModel::class.java]
}
private var nameStr = ""
private var pwdStr = ""
//判断请求状态
private var isRequestLogin = false
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.tvLogin.setOnClickListener {
nameStr = binding.etLoginName.text.trim().toString()
pwdStr = binding.etLoginPwd.text.trim().toString()
if (nameStr.isEmpty() || pwdStr.isEmpty()) {
Toast.makeText(this, "请输入账号或密码", Toast.LENGTH_SHORT).show()
} else {
requestLogin(nameStr, pwdStr)
}
}
}
//请求登录
private fun requestLogin(username: String, password: String) {
lifecycleScope.launch {
loginViewModel.requestLogin(
this@LoginActivity,
username,
password,
object : IResult<LoginBean.LoginContent> {
override fun startView() {
//开始进行请求,此时请求状态为true
isRequestLogin = true
//展示显示请求登录的加载中的加载框
showLogin()
}
override fun successView(content: LoginBean.LoginContent?) {
//登录成功之后,调用登录成功加载框方法
showLoginSuccess()
//请求状态变为false
isRequestLogin = false
}
override fun failedView(failStr: String) {
if (isRequestLogin) {
//登录失败的时候,如果此时处于请求转态的话,展示失败加载框
showLoginFailed()
Log.e(TAG, "登录失败: $failStr")
}
}
override fun errorView(exception: Throwable) {
if (isRequestLogin) {
//登录错误的时候,如果此时处于请求转态的话,展示失败加载框
showLoginFailed()
Log.e(TAG, "登录错误: $exception")
}
}
})
}
}
//重试,在加载失败或者错误时,点击屏幕可以重新加载操作
override fun onLoadRetry() {
super.onLoadRetry()
requestLogin(nameStr, pwdStr)
}
//监听返回键
override fun onBackPressed() {
if (isRequestLogin) {
//当处于请求加载状态的时候,点击返回按钮,显示加载成功(加载成功的界面其实不会显示,因为
//根本没有这个页面,同时看上面GlobalLoadingStatusView 类的代码就可以知道,
//当成功的时候,视图的visibility==Gone)
showLoginSuccess()
isRequestLogin = false
} else {
super.onBackPressed()
}
}
}
OVER