Android Retrofit取消请求异常分析

Retrofit取消请求封装和分析处理

   此篇文章适合okhttp和retrofit使用者,如果不是请观看其他文章,如果是的那你就发达了,赚到了。

   首先我们在封装网络请求的时候会遇到activity等视图已经关闭,然而网络请求并没有关闭的现象,毕竟网络请求为异步处理和加载,不处理就会造成异常。那么接下来我们就需要管理和处理这个现象,那么怎么处理呢,请继续看文章分析。

    一:管理和处理call

   需要在baseactivity和basefragment中进行封装call拿到call放入list集合,进行有序放入和有序取消,在onDestroy中进行统一取消请求,这样就避免了,空指针异常。如下代码所示:


import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

import com.jaeger.library.StatusBarUtil;
import com.umeng.message.PushAgent;

import java.util.ArrayList;
import java.util.List;

import butterknife.ButterKnife;
import butterknife.Unbinder;
import edu.com.gaiwen.firstchoice.utils.AppManager;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import retrofit2.Call;

/**
 * Created by xfc on 2017/6/5.
 * 用于activity基类
 */
public abstract class BaseActivityxfc extends AppCompatActivity implements View.OnClickListener {
    private Unbinder unbind;
    private CompositeDisposable compositeDisposable;
    private List<Call> calls;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        unbind = ButterKnife.bind(this);
        StatusBarUtil.setColor(this, Color.parseColor("#0ab6d8"));
        PushAgent.getInstance(this).onAppStart();
        AppManager.getAppManager().addActivity(this);
        onView();
    }

    public void addCalls(Call call) {
        if (calls == null) {
            calls = new ArrayList<>();
        }
        calls.add(call);
    }

    private void callCancel() {
        if (calls != null && calls.size() > 0) {
            for (Call call : calls) {
                if (!call.isCanceled())
                    call.cancel();
            }
            calls.clear();
        }
    }

    public void addDisposable(Disposable disposable) {
        if (compositeDisposable == null) {
            compositeDisposable = new CompositeDisposable();
        }
        compositeDisposable.add(disposable);
    }

    protected void cancelDispose() {
        if (compositeDisposable != null) {
            compositeDisposable.dispose();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideKeyboard(v, ev)) {
                hideKeyboard(v.getWindowToken());
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘,因为当用户点击EditText时则不能隐藏
     *
     * @param v
     * @param event
     * @return
     */
    private boolean isShouldHideKeyboard(View v, MotionEvent event) {
        if (v != null && (v instanceof EditText)) {
            int[] l = {0, 0};
            v.getLocationInWindow(l);
            int left = l[0],
                    top = l[1],
                    bottom = top + v.getHeight(),
                    right = left + v.getWidth();
            if (event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom) {
                // 点击EditText的事件,忽略它。
                return false;
            } else {
                v.clearFocus();
                return true;
            }
        }
        // 如果焦点不是EditText则忽略,这个发生在视图刚绘制完,第一个焦点不在EditText上,和用户用轨迹球选择其他的焦点
        return false;
    }

    /**
     * 获取InputMethodManager,隐藏软键盘
     *
     * @param token
     */
    private void hideKeyboard(IBinder token) {
        if (token != null) {
            InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    /**
     * 进行销毁解绑
     */
    @Override
    protected void onDestroy() {
        cancelDispose();
        callCancel();
        super.onDestroy();
        AppManager.getAppManager().finishActivity(this);
        if (unbind != null) {
            unbind.unbind();
        }
    }

    /**
     * 加载布局
     */
    protected abstract int getLayoutId();

    /**
     * 初始化操作
     */
    protected abstract void onView();
}

    basefragment同理,不需要的代码看看就算了,List<Call> calls;主要是这个集合的使用。

    二:进行异步判断处理

    在使用上面判断中发现这样处理和管理call,在异步中依然会走onFailure方法,会爆出异常

 @Override
    public void onFailure(Call<ResponseBody> call, Throwable e) {
        if (!call.isCanceled()) {
            catchException(e);
            onFailure();
        }
    }

    (使用okhttp方法略有不同,但功能一致),这样我们就需要判断call.isCanceled(),我们发现如果是取消请求,则这个方法会返回为true,如果不是则为false。

    三:进行源码分析

  public void cancel() {
    canceled = true;

    okhttp3.Call call;
    synchronized (this) {
      call = rawCall;
    }
    if (call != null) {
      call.cancel();
    }
  }

  @Override public boolean isCanceled() {
    if (canceled) {
      return true;
    }
    synchronized (this) {
      return rawCall != null && rawCall.isCanceled();
    }
  }
    我们发现只有在取消请求后isCanceled才返回为true,其他状况下则为false,不放心的话我们看下rxjava里面进行的处理,
 @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    observer.onSubscribe(new CallDisposable(call));

    boolean terminated = false;
    try {
      Response<T> response = call.execute();
      if (!call.isCanceled()) {
        observer.onNext(response);
      }
      if (!call.isCanceled()) {
        terminated = true;
        observer.onComplete();
      }
    } catch (Throwable t) {
      Exceptions.throwIfFatal(t);
      if (terminated) {
        RxJavaPlugins.onError(t);
      } else if (!call.isCanceled()) {
        try {
          observer.onError(t);
        } catch (Throwable inner) {
          Exceptions.throwIfFatal(inner);
          RxJavaPlugins.onError(new CompositeException(t, inner));
        }
      }
    }
  }

我们发现rxjava中进行判断和处理也是进行的这个判断处理,这样就可以放心的使用了,欢迎大家一起探讨。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值