Android 常见问题十: 网络请求

Retrofit+Okhttp+Rxjava

请求实例类获取retrofit
package com.zqq.shell.http

import android.util.Log
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.util.concurrent.TimeUnit

class HttpCreator {
    companion object{
        val BASE_URL = "http://www.baidu.com"  //基础路径
        private const val timeOut:Long = 60 //30秒超时
        var baseUrlInterceptor: BaseUrlInterceptor = BaseUrlInterceptor()
        var okhttpClient: OkHttpClient

        var loggingInterceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
            override fun log(message: String) {
                //打印retrofit日志
                Log.i("RetrofitLog", "retrofitBack = $message")
            }
        })

        init {
            loggingInterceptor.level =HttpLoggingInterceptor.Level.BODY
            var builder:OkHttpClient.Builder =OkHttpClient.Builder()
                .connectTimeout(timeOut, TimeUnit.SECONDS)
                .readTimeout(timeOut, TimeUnit.SECONDS)
                .writeTimeout(timeOut, TimeUnit.SECONDS)
                .addInterceptor(baseUrlInterceptor)
                .addInterceptor(loggingInterceptor)
            okhttpClient=builder.build();
        }

        @Volatile
        var retrofit: Retrofit? = null

        fun getInstance():Retrofit{
            if (retrofit == null) {
                synchronized(this) {
                    if (retrofit == null) {
//                  Gson gson = new GsonBuilder().setLenient().create();
                    retrofit = Retrofit.Builder()
                            .baseUrl(BASE_URL)
//                           .addConverterFactory(GsonConverterFactory.create()) //配置转化库-->
//                           .addConverterFactory(GsonConverterFactory.create(gson)) //配置转化库 Gson解析失败,不报错崩溃
                            .addConverterFactory(ScalarsConverterFactory.create()) //配置转化库 Gson解析失败,不报错崩溃
                            .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //配置回调库,采用RxJava
                            .client(okhttpClient)
                            .build()
                    }
                }
            }

            return retrofit!!
        }
    }
}
拦截器
package com.zqq.shell.http;

import java.io.IOException;

import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class BaseUrlInterceptor implements Interceptor
{
    @Override
    public Response intercept(Chain chain) throws IOException
    {
        // 获取request
        Request request = chain.request();
        // 从request中获取原有的HttpUrl实例oldHttpUrl
        HttpUrl oldHttpUrl = request.url();
        // 获取request的创建者builder
        Request.Builder builder = request.newBuilder()
                .addHeader("Content-Type", "application/json; charset=UTF-8")  ;
        // 从request中获取headers,通过给定的键url_name
//        List<String> headerValues = request.headers("url_name");
//        if (headerValues != null && headerValues.size() > 0)
//        {
//            // 如果有这个header,先将配置的header删除,因此header仅用作app和okhttp之间使用
//            builder.removeHeader("url_name");
//            // 匹配获得新的BaseUrl
//            String headerValue = headerValues.get(0);
//            HttpUrl newBaseUrl = null;
//            if ("URL1".equals(headerValue))
//            {
//                newBaseUrl = HttpUrl.parse(HttpCreate.BASE_URL);
//            }
//            else if ("URL2".equals(headerValue))
//            {
//                newBaseUrl = HttpUrl.parse(HttpCreate.BASE_URL1);
//            }
//            else
//            {
//                newBaseUrl = oldHttpUrl;
//            }
//            LogUtils.i("newBaseUrl>>"+newBaseUrl);
//            // 重建新的HttpUrl,修改需要修改的url部分
//            HttpUrl newFullUrl = oldHttpUrl
//                    .newBuilder()
//                    // 更换网络协议
//                    .scheme(newBaseUrl.scheme())
//                    // 更换主机名
//                    .host(newBaseUrl.host())
//                    // 更换端口
//                    .port(newBaseUrl.port())
//                    .build();
//            // 重建这个request,通过builder.url(newFullUrl).build();
//            // 然后返回一个response至此结束修改
//            return chain.proceed(builder.url(newFullUrl).build());
//        }
        return chain.proceed(request);
    }
}

请求对话框

package com.zqq.shell.http;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;

import com.zqq.shell.R;


public class HttpDialog extends Dialog {
    public HttpDialog(@NonNull Context context) {
        this(context,0);
    }

    public HttpDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dialog_http_request);

        initView();
        initData();
    }
    TextView tv;
    LinearLayout ll;
    private void initView() {
        ll = findViewById(R.id.ll);
        tv = findViewById(R.id.tv);
    }

    private void initData() {

    }

    public void setMessage(String msg){
        tv.setText(msg+"...");
    }
}

对话框布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center"
    android:minWidth="140dp"
    android:minHeight="140dp"
    android:padding="20dp"
    android:alpha="0.85"
    android:id="@+id/ll"
    android:background="@drawable/http_dialog_bg"
    >

    <ProgressBar
        android:id="@+id/ll_pb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@android:style/Widget.Holo.ProgressBar.Large"
        android:indeterminateTint="@color/main_color"
        />
    <TextView
        android:id="@+id/tv"
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="获取数据中..."
        android:textColor="@color/main_color"
        android:maxLines="1"
        android:minLines="1"
        />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ffffff" />
    <stroke
        android:width="0.8dp"
        android:color="#ffffff"
        />
    <!-- 圆角 -->
    <corners android:radius="6dp" />
</shape>

返回结果类
package com.zqq.shell.http;

public class Result<T> {
    private String str;
    private boolean success;
    private T result;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }

    @Override
    public String toString() {
        return "Result{" +
                "str='" + str + '\'' +
                ", success=" + success +
                ", result=" + result +
                '}';
    }
}

通过以上内容,封装BaseActivity/BaseFragment

检查网络链接
 open fun checkInternet(): Boolean {
        var result =false
        val connectivityManager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            connectivityManager.run {
                getNetworkCapabilities(activeNetwork).run {
                    result  = hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                             hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                             hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
                }
            }
        } else {
            connectivityManager?.run {
                activeNetworkInfo?.run {
                    if (type == ConnectivityManager.TYPE_WIFI) {
                        result = true
                    } else if (type == ConnectivityManager.TYPE_MOBILE) {
                        result = true
                    }
                }
            }
        }
        return result
    }

重写的BaseActivity

package com.zqq.shell.activity

import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import butterknife.ButterKnife
import com.zqq.shell.MyApplication
import com.zqq.shell.R
import com.zqq.shell.http.HttpDialog
import com.zqq.shell.utils.KeyboardUtils
import com.zqq.shell.utils.StatusBarUtil
import com.zqq.shell.utils.ToastUtils
import es.dmoral.toasty.Toasty
import io.reactivex.Observer
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import org.json.JSONException
import org.json.JSONObject

open abstract class BaseActvity :AppCompatActivity() {

    var msg = "请求中"
    var unDismiss = false //是否隐藏请求对话框
    public lateinit var app:MyApplication
    lateinit var dialog: HttpDialog
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //设备不休眠
        window.setFlags(
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
        )

        val contentView = initContentView() //设置contentView
        setContentView(contentView)

        ButterKnife.bind(this)  //butterknife

        //依赖 implementation 'com.readystatesoftware.systembartint:systembartint:1.0.3' //状态栏颜色改变
        StatusBarUtil.setStatusBarColor(this, R.color.main_color) //设置状态栏颜色

        app = MyApplication.instance()
        app.addActivity(this)

        Toasty.Config.reset()
        Toasty.Config.getInstance()
            .tintIcon(true) // optional (apply textColor also to the icon)
            //                .setToastTypeface(@NonNull Typeface typeface) // optional
            .setTextSize(22) // optional
            .allowQueue(true) // optional (prevents several Toastys from queuing)
            .apply() // required


        dialog = HttpDialog(this, R.style.http_dialog) //请求对话框
        dialog.create()

        initView(savedInstanceState) //初始化view
        initData() //初始化数据
    }

    abstract fun initContentView():Int
    abstract fun initView(savedInstanceState: Bundle?)
    abstract fun initData()


    open fun checkInternet(): Boolean {
        var result =false
        val connectivityManager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            connectivityManager.run {
                getNetworkCapabilities(activeNetwork).run {
                    result  = hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                             hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                             hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
                }
            }
        } else {
            connectivityManager?.run {
                activeNetworkInfo?.run {
                    if (type == ConnectivityManager.TYPE_WIFI) {
                        result = true
                    } else if (type == ConnectivityManager.TYPE_MOBILE) {
                        result = true
                    }
                }
            }
        }
        return result
    }


    /**
     * 定义网络请求回调
     */
    private val compositeDisposable = CompositeDisposable()

    inner abstract class CallBackObserver<T> : Observer<T> {
        private var disposable: Disposable? = null
        override fun onSubscribe(d: Disposable) { //执行开始操作,比如显示请求对话框
            KeyboardUtils.hideKeyBoard(this@BaseActvity)
            val checkInternet: Boolean = checkInternet()
            if (!checkInternet) {
                ToastUtils.showMessage(this@BaseActvity, "您的设备未联网,请检查!")
                d.dispose() //无网络时时解除订阅
                return
            }
            if (dialog != null) {
                dialog.show()
                dialog.setMessage(msg)
                if (unDismiss) {
                    dialog.setCancelable(false)
                    dialog.setCanceledOnTouchOutside(false)
                }
            }
            disposable = d
            compositeDisposable.add(d)
            onStartNet(d)
        }

        override fun onNext(o: T) { //执行结果分类操作,比如错误提示
            try {
                val jsonObject = JSONObject(o.toString())
                Log.i("zqq", "返回数据>$jsonObject")
                val aBoolean = jsonObject.getBoolean("result")
                if (aBoolean) {
                    onSuccess(jsonObject.toString() as T)
                } else {
                    onFail(jsonObject.getString("strMsg"))
                    ToastUtils.showMessage(this@BaseActvity, jsonObject.getString("strMsg"))
                    if ("登录超时" == jsonObject.getString("strMsg")) {
                        app.removeAllActivity()
                        startActivity(Intent(this@BaseActvity, LoginActivity::class.java))
                    }
                }
            } catch (e: JSONException) {
                e.printStackTrace()
                onFail("请求超时,请重试!")
                ToastUtils.showMessage(this@BaseActvity, "请求超时,请重试!")
            }
        }

        override fun onError(e: Throwable) { //网络请求错误提示
            Log.i("zqq", "网络请求》》》onError>>$e")
            if (e.toString().contains("SocketTimeoutException")) {
                onFail("请求超时,请重试!")
                ToastUtils.showMessage(this@BaseActvity, "请求超时,请重试!")
            } else {
                ToastUtils.showMessage(this@BaseActvity, "请求失败,请重试!")
            }
            onFail("错误!")
            if (dialog != null) {
                dialog.dismiss()
            }
            disposable!!.dispose() //错误时时解除订阅
        }

        override fun onComplete() {
            if (dialog != null) {
                dialog.dismiss()
            }
            disposable!!.dispose() //完成时解除订阅
        }

        abstract fun onSuccess(success: T)
        abstract fun onStartNet(d: Disposable?)
        abstract fun onFail(fail: String?)
    }


    override fun onDestroy() {
        super.onDestroy()
        app.removeActivity(this)
        compositeDisposable.clear() //界面销毁时,必须解除所有订阅
    }

    /**
     * 设置请求时对话框提示语
     */
    open fun setDialogMsg(msg: String?) {
        this.msg = msg!!
    }

    /**
     * 设置对话框不可关闭
     */
    open fun unDismiss(unDismiss: Boolean?) {
        this.unDismiss = unDismiss!!
    }
}

使用

创建接口

package com.zqq.shell.api

import io.reactivex.Observer
import okhttp3.RequestBody

interface LoginApi {
    /**
     * 登录
     */
    fun login(info: String, observer: Observer<String>)
}

创建实现类

package com.zqq.shell.api.imp

import com.zqq.shell.api.LoginApi
import com.zqq.shell.http.HttpCreator
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import retrofit2.http.Body
import retrofit2.http.POST

public class LoginApiImp() :LoginApi{

    val loginService: LoginService = HttpCreator.getInstance().create(LoginService::class.java)


    override fun login(info: String, observer: Observer<String>) {
        val requestBody =info.toRequestBody("application/json;charset=utf-8".toMediaType()) //Post请求时使用

        val login = loginService.login(requestBody)
        login!!.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(observer)

    }

    interface LoginService {
        /**
         * 登录接口
         * @return
         */
        @POST("/")
        fun login(@Body body: RequestBody?): Observable<String>?
    }

}

GET请求 请求后携带json字符串

 /**
         * 
         * @param body
         * @return
         */
        @GET("/{body}")
        Observable<String> searchCustomerList(@Path("body") String body);
 @GET("http://")
        Observable<String> getServer(@Query("username") String username);

Activity中使用

  val loginApi = LoginApiImp()
  
private fun login() {

        val jsonDevice = JSONObject()
        jsonDevice.put("username", el_username.text)
        jsonDevice.put("password", el_password.text)

        loginApi.login(jsonDevice.toString(),object:CallBackObserver<String>(){
            override fun onSuccess(success: String) {
                Log.i("zqqq",success);
            }

            override fun onStartNet(d: Disposable?) {

            }

            override fun onFail(fail: String?) {

            }

        })
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值