Android上发送HTTP请求,一般有两个方式:HttpURLConnection和HttpClient。HttpClient由于存在API数量多,扩展困难缺点,Android6.0开始HttpClient的功能完全移除,被废弃。
Android 9.0开始,应用程序默认值允许使用HttpS类型的网络请求。如果测试想请求Http的请求,需要配置network-security-config
进行网络请求,请先配置权限:<uses-permission android:name="android.permission.INTERNET" />
1.纯HttpURLConnection进行数据请求
private fun doRequestWithHttpURLConnection(){
thread {
var connection:HttpURLConnection?=null
val response = StringBuilder()
val url = URL("https://www.baidu.com/")
connection = url.openConnection() as HttpURLConnection
connection.connectTimeout = 8000
connection.readTimeout = 8000
val inputStream = connection.inputStream
val reader = BufferedReader(InputStreamReader(inputStream))
reader.use {
reader.forEachLine {
response.append(it)
}
}
showResponse( response.toString())
}
}
private fun showResponse(content: String) {
runOnUiThread {
responseText.text = content
}
}
注意:网络请求需要放置在子线程,刷新UI需要在UI线程
2.使用OKHttp
在开源盛行的今天,网络方面有很多开源的框架,其中OkHttp是比较优秀的。
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
使用OkHttp需要添加这个依赖,添加之后会自动加载两个库一个是OkHttp库,一个是Okio库,后者是前者通信的基础。
fun sendOkHttpRequest(address:String,callback:Callback){
val client=OkHttpClient()
val request=Request.Builder()
.url(address)
.build()
client.newCall(request).enqueue(callback)
}
//在activity调用
sendOkHttpRequest("https://www.baidu.com/", object :Callback {
override fun onFailure(call: Call, e: IOException) {
TODO("Not yet implemented")
}
override fun onResponse(call: Call, response: Response) {
val string = response.body?.string()
showResponse(string)
}
})
3.Retrofit 库的使用
retrofit库,是在okHttp的基础上继续封装的库,是目前最好的网络框架。OkHttp侧重在底层通信的实现,Retrofit侧重是上层接口的封装。
常用的请求注解:
@GET :请求服务器啥的数据
@POST:用于向服务器提交数据
@PUT:修复服务器上的数据
@DELETE:删除服务器上的数据
object RetrofitCreator {
private const val BASE_URL="https://vsapi.meishesdk.com"
private val retrofit=Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build()
fun <T> create(retrofitClass:Class<T>):T= retrofit.create(retrofitClass)
inline fun <reified T> create(): T = create(T::class.java)
}
定义一个单例的Retrofit的创建类
//get 请求传参数
@GET("/api/authorization/ST/current")
fun getSTLicFileInfo(@Query("appId") appId:String): Call<LicenseInfo>
定义一个接口,通过@Query来传递参数,返回一个对象。
val appService = RetrofitCreator.create<AppService>()
appService.getSTLicFileInfo(App.getAppId()).enqueue(object : Callback<LicenseInfo>{
override fun onResponse(call: Call<LicenseInfo>, response: Response<LicenseInfo>) {
Log.d("test","onResponse")
}
override fun onFailure(call: Call<LicenseInfo>, t: Throwable) {
Log.d("test","onFailure")
}
})
使用的时候通过上面的方式就行调用
//get请求,通过path 来实现分页接口
@GET("{page}/data.json")
fun getData(@Path("page") page:Int):Call<List<LicenseInfo>>
通过使用Path来定义分页请求的接口
@DELETE("data/{id}")
fun deleteLic(@Path("id") id:String):Call<ResponseBody>
删除一条数据,返回值是ResponseBody,表示客户端对于服务器响应的数据不关心,也不解析。
@POST("data/create")
fun createData(@Body data:Data):Call<ResponseBody>
post 请求通过@Body来提交Data类型的数据
//静态传Header
@Headers("User-Agent:okhttp","Cache-Control:max-age=0")
@GET("data.json")
fun getData():Call<Data>
//动态传Header
@GET("data.json")
fun getData( @Header("Cache-Control") cacheControl:String):Call<Data>
带着Header来请求,这个形式是静态的传递Header,如果希望动态传递Header需要用到
4.Retrofit实现下载文件
//动态url实现下载 用于小文件下载
@GET
fun downloadFile(@Url url:String):Call<ResponseBody>
通过@Url来实现动态url来下载文件,由于全部写入内内存,所以不能下载大文件,否则会OOM
val create = RetrofitCreator.create<AppService>()
val downloadFile = create.downloadFile("http://196.168.1.200/text.txt")
downloadFile.enqueue(object : retrofit2.Callback<ResponseBody>{
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.isSuccessful){
val writtenToDisk: Boolean = writeResponseBodyToDisk(response.body())
}
}
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
TODO("Not yet implemented")
}
})
//将数据写入文件
private boolean writeResponseBodyToDisk(ResponseBody body) {
try {
// todo change the file location/name according to your needs
File futureStudioIconFile = new File(getExternalFilesDir(null) + File.separator + "Icon.png");
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
long fileSize = body.contentLength();
long fileSizeDownloaded = 0;
inputStream = body.byteStream();
outputStream = new FileOutputStream(futureStudioIconFile);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
Log.d(TAG, "file download: " + fileSizeDownloaded + " of " + fileSize);
}
outputStream.flush();
return true;
} catch (IOException e) {
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
return false;
}
}
如果是大文件下载
@Streaming
@GET
fun downloadBigFile(@Url url:String):Call<ResponseBody>
下载大文件只需要添加@Streaming的方式来实现大文件下载