我看到的主题,如如何下载文件在Android使用改造库?,他们使用@Streaming
和RxJava/回调。
我有Kotlin、协同程序、改装2.6.0和类似于中的查询https://stackoverflow.com/a/56473934/2914140:
@FormUrlEncoded
@Streaming
@POST("export-pdf/")
suspend fun exportPdf(
@Field("token") token: String
): ExportResponse
我有一个改装客户:
retrofit = Retrofit.Builder()
.baseUrl(SERVER_URL)
.client(okHttpClient)
.build()
service = retrofit.create(Api::class.java)
如果令牌参数正确,查询将返回PDF文件:
%PDF-1.4
%����
...
如果是错误的,它将返回带有错误描述的JSON:
{
"success": 0,
"errors": {
"message": "..."
}
}
因此,ExportResponse是一个包含JSON字段POJO的数据类。
我无法使用访问文件数据
Response response = restAdapter.apiRequest();
try {
//you can now get your file in the InputStream
InputStream is = response.getBody().in();
} catch (IOException e) {
e.printStackTrace();
}
因为ExportSolutions是一个数据类,所以val响应: ExportSolutions=interactor.exportPdf(令牌)
将返回数据,而不是Retromet对象。
多亏了@Andreitana,我发现了一个错误。请求定义中的suspend
中存在问题。所有其他请求保留其suspend
修饰符,但此请求将其删除。我改变了密码,所以。
interface Api {
@FormUrlEncoded
@Streaming
@POST("export-pdf/")
fun exportPdf(
@Field("token") token: String
): Call<ResponseBody>
// Any another request. Note 'suspend' here.
@FormUrlEncoded
@POST("reject/")
suspend fun reject(): RejectResponse
}
然后在它的实现中,apimpl:
class ApiImpl : Api {
private val retrofit by lazy { ApiClient.getRetrofit().create(Api::class.java) }
override fun exportPdf(
token: String
): Call<ResponseBody> =
retrofit.exportPdf(token)
override suspend fun reject(): RejectResponse =
// Here can be another instance of Retrofit.
retrofit.reject()
}
改装客户端:
class ApiClient {
companion object {
private val retrofit: Retrofit
init {
val okHttpClient = OkHttpClient().newBuilder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build()
val gson = GsonBuilder().setLenient().create()
retrofit = Retrofit.Builder()
.baseUrl(SERVER_URL)
.client(okHttpClient)
// .addConverterFactory(GsonConverterFactory.create(gson)) - you can add this line, I think.
.build()
}
fun getRetrofit(): Retrofit = retrofit
}
互动者:
interface Interactor {
// Note 'suspend' here. This is for coroutine chain.
suspend fun exportPdf(
token: String
): Call<ResponseBody>
}
class InteractorImpl(private val api: Api) : Interactor {
override suspend fun exportPdf(
token: String
): Call<ResponseBody> =
api.exportPdf(token)
}
然后在片段中:
private fun exportPdf(view: View, token: String) {
showProgress(view)
launch(Dispatchers.IO) {
try {
val response = interactor.exportPdf(token).execute()
var error: String? = null
if (response.headers().get("Content-Type")?.contains(
"application/json") == true) {
// Received JSON with an error.
val json: String? = response.body()?.string()
error = json?.let {
val export = ApiClient.getGson().fromJson(json,
ExportPdfResponse::class.java)
export.errors?.common?.firstOrNull()
} ?: getString(R.string.request_error)
} else {
// Received PDF.
val buffer = response.body()?.byteStream()
if (buffer != null) {
val file = context?.let { createFile(it, "pdf") }
if (file != null) {
copyStreamToFile(buffer, file)
launch(Dispatchers.Main) {
if (isAdded) {
hideProgress(view)
}
}
}
}
}
if (error != null) {
launch(Dispatchers.Main) {
if (isAdded) {
hideProgress(view)
showErrorDialog(error)
}
}
}
} catch (e: Exception) {
launch(Dispatchers.Main) {
if (isAdded) {
showErrorDialog(getString(R.string.connection_timeout))
hideProgress(view)
}
}
}
}
}
您可以将exportPdf
的返回类型更改为Call
val response = restAdapter.apiRequest().execute()
if (response.isSuccessful) {
response.body()?.byteStream()//do something with stream
} else {
response.errorBody()?.string()//try to deserialize json from string
}
最新消息
以下是我的测试的完整列表:
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.http.GET
import retrofit2.http.Url
import java.io.File
import java.io.InputStream
fun main() {
val queries = buildQueries()
check(queries, "http://127.0.0.1:5000/error")
check(queries, "http://127.0.0.1:5000/pdf")
}
private fun check(queries: Queries, url: String) {
val response = queries.exportPdf(HttpUrl.get(url)).execute()
if (response.isSuccessful) {
response.body()?.byteStream()?.saveToFile("${System.currentTimeMillis()}.pdf")
} else {
println(response.errorBody()?.string())
}
}
private fun InputStream.saveToFile(file: String) = use { input ->
File(file).outputStream().use { output ->
input.copyTo(output)
}
}
private fun buildRetrofit() = Retrofit.Builder()
.baseUrl("http://127.0.0.1:5000/")
.client(OkHttpClient())
.build()
private fun buildQueries() = buildRetrofit().create(Queries::class.java)
interface Queries {
@GET
fun exportPdf(@Url url: HttpUrl): Call<ResponseBody>
}
这里是用烧瓶建造的简单服务器:
from flask import Flask, jsonify, send_file
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
@app.route('/error')
def error():
response = jsonify(error=(dict(body='some error')))
response.status_code = 400
return response
@app.route('/pdf')
def pdf():
return send_file('pdf-test.pdf')
对我来说一切都很好
更新2
看起来您必须在Api中编写以下内容:
@FormUrlEncoded
@Streaming // You can also comment this line.
@POST("export-pdf/")
fun exportPdf(
@Field("token") token: String
): Call<ResponseBody>
我使用改造2.7.1与静态编程语言协程。 我的改装服务定义如下: 此调用返回HTTP 204无内容响应,这会导致改装时崩溃: 如何使用协程处理改造中的204响应而不崩溃?
我正在使用Reformation 2.0下载文件。问题是未调用<code>使 这是我的界面: 这是我的下载代码:
我使用Refught2调用kotlin协同程序的API,但API的状态代码为200、400和700。当请求API和响应状态代码为400或700时,“withTimeout”协同程序可能会异常崩溃。我想处理带有“withTimeout”协同程序的状态代码400和700响应消息,或者如何自定义“协同程序”谢谢。 这是我的密码 错误消息
最近,我通过学习CodeLabs教程学习了kotlin coroutine。经过一些实践,我想知道我是否可以用java编写相同的代码。首先,我在MyKotlinFragment中编写了一个简单的kotlin代码。kt文件如下: 在我的片段中调用了;它起作用了。 接下来,我打开了一个名为MyRoutineFragment的java文件。java在同一个项目中,但我无法让它工作。 我无法将第一个文件转
我正在实现一个ASP api来完成所有Docusign api流(获取登录信息,获取令牌,发送要签名的信封,下载信封文档)。现在我试图在浏览器中显示一个下载的文档,该文档是空白的。我正在从docusign接收文档字节内容,并试图将其呈现在iframe中。 docusign发送的PDF内容如下 更新 如果文档超过1页,则可以看到所有页面,全部为空白······
我正在尝试使用python3构建带有GUI的youtube下载程序。在学习了python的基础知识之后,我正在尝试构建一个。我正在使用“pafy”和“TKinter”模块。 以下是GUI 1中涉及的小部件。一个输入字段,用于输入URL 2。在它旁边粘贴按钮3。媒体选择下拉菜单4。另一个下拉菜单列出介质质量(取决于以前的介质输入)5。最后是下载按钮 这是我的密码 我被“下载功能”卡住了。我是否正确使