gpt4 book ai didi

android - 如何获取 JsonReader 字节来计算百分比

转载 作者:行者123 更新时间:2023-11-30 00:47:16 31 4
gpt4 key购买 nike

我需要下载包含 20k 项的 Json 文件,同时我需要在 TextView 中显示百分比。现在我只测试代码的流程,所以我显示一个包含当前百分比的简单日志。所以我创建了一个 Observable 并且我这样做了:

private void downloadAirports()
{
final OkHttpClient mOkHttpClient = new OkHttpClient();

final Request mRequest = new Request.Builder().url(SERVICE_ENDPOINT).build();

Observable.create(new Observable.OnSubscribe<String>()
{
@Override
public void call(Subscriber<? super String> subscriber)
{
try {
InputStream inputStream;
okhttp3.Response response = mOkHttpClient.newCall(mRequest).execute();
if (response.isSuccessful())
{
inputStream = response.body().byteStream();
long len = response.body().contentLength();

Log.d("str",String.valueOf(len));

String progress = "0";
subscriber.onNext(progress);

final int bufferSize = 1024;
boolean flag = false;
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
Reader in = new InputStreamReader(inputStream, "UTF-8");

long total = 0;
airp = new ArrayList<AirportObject>();
int count =0;

Gson gson = new Gson();
JsonReader reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8"));
airp = new ArrayList<>();
long i = 0;
reader.beginArray();

while (reader.hasNext())
{

AirportObject message = gson.fromJson(reader, AirportObject.class);
airp.add(message);
i++;
byte [] arr = message.toString().getBytes();
total = total + arr.length;

Log.d("%",String.valueOf(total));

double p = total/len * 100;


subscriber.onNext(String.valueOf(p));
}


reader.endArray();
reader.close();






//airp = Arrays.asList(airportArray);


subscriber.onCompleted();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).subscribeOn(Schedulers.newThread())
.subscribe(new Subscriber<String>() {

long size, perc;
public void onCompleted()
{
Log.wtf("on complete","On complete");
}

@Override
public void onError(Throwable e)
{
e.printStackTrace();
}

@Override
public void onNext(final String progress) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run()
{
// Log.d("%",progress);
// textView.setText("Download aeroporti in corso:"+progress+"%");
}
});
}
});
}

但是我给了变量len(有效字节数)和变量total两个不同的值。那么while循环中如何获取JsonReader下载的有效字节值呢?

谢谢

最佳答案

您可以重新考虑您的进度模型,以使其更加简单和分离。如果将进度状态封装到 InputStream 中会怎样 decorator并在阅读时暴露它?

它是如何工作的?首先,您必须封装要装饰的真实输入流。还需要一些中间状态来计算读取的字节数并将该值与预期长度值进行比较。一旦某个事件在某种情况下发生,只需通过已经封装的订阅者触发比率值。下面的输入流装饰器使用 Float 比率,其中值始终在 [0;1] 范围内。为什么?让您的 View 决定如何呈现标准化比率: TextView 中的百分比、进度条或其他任何内容。百分比基本上只是一个人性化的未规范化值,而在给出比率时,您要确保始终传递0..1值并且不传递关心生成器站点的“用户友好性”(想象一下,如果有一天您将公开 promille,hm-m-m —— 这会在其他地方破坏您的代码,这些代码会期望百分比而不是 promilles)。

public final class ProgressInputStream
extends InputStream {

private final Subscriber<? super Float> subscriber;
private final InputStream inputStream;
private final long expectedLength;
private final long lengthPerPercent;

private long actualLength;
private long currentChunkLength;

private ProgressInputStream(final Subscriber<? super Float> subscriber, final InputStream inputStream, final long expectedLength) {
this.subscriber = subscriber;
this.inputStream = inputStream;
this.expectedLength = expectedLength;
lengthPerPercent = (long) ceil((double) expectedLength / 100);
}

public static InputStream progressInputStream(final Subscriber<? super Float> subscriber, final InputStream inputStream, final long expectedLength) {
return new ProgressInputStream(subscriber, inputStream, expectedLength);
}

@Override
public int read()
throws IOException {
return (int) count(inputStream.read());
}

@Override
public int read(final byte[] bytes)
throws IOException {
return (int) count(inputStream.read(bytes));
}

@Override
public int read(final byte[] bytes, final int offset, final int length)
throws IOException {
return (int) count(inputStream.read(bytes, offset, length));
}

@Override
public long skip(final long n)
throws IOException {
return count(inputStream.skip(n));
}

@Override
public void close()
throws IOException {
inputStream.close();
}

private long count(final long read) {
if ( read != -1 ) {
if ( actualLength == 0 ) {
subscriber.onNext(0F);
}
currentChunkLength += read;
actualLength += read;
if ( currentChunkLength >= lengthPerPercent ) {
currentChunkLength = 0;
if ( actualLength < expectedLength ) {
subscriber.onNext((float) actualLength / expectedLength);
} else if ( actualLength == expectedLength ) {
subscriber.onNext(1F);
subscriber.onCompleted();
} else {
throw new AssertionError("Must never happen. A bug in the code around?");
}
} else if ( actualLength == expectedLength ) {
subscriber.onNext(1F);
subscriber.onCompleted();
}
}
return read;
}

}

现在,将进度计算器封装在装饰器中,典型的用法可能如下所示:

Observable
.<Float>create(subscriber -> {
final File file = new File("/tmp/some.json");
try ( final InputStream inputStream = progressInputStream(subscriber, new BufferedInputStream(new FileInputStream(file)), file.length());
final JsonReader reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8")) ) {
reader.beginArray();
while ( reader.hasNext() ) {
gson.<AirportObject>fromJson(reader, AirportObject.class);
}
reader.endArray();
} catch ( final IOException ex ) {
throw new RuntimeException(ex);
}
})
.subscribe(new Subscriber<Float>() {
@Override
public void onNext(final Float ratio) {
out.printf("Read: %s%%\n", (long) (ratio * 100));
}

@Override
public void onCompleted() {
out.println("Downloaded");
}

@Override
public void onError(final Throwable ex) {
throw new RuntimeException(ex);
}
});

检查一下,现在您不必在解析 JSON 时计算进度,从而使您的代码更清晰。此外,您可以在其他地方重复使用这样的流,而不仅仅是 Gson 等。

我只在桌面系统上测试过它,而不是在真实设备上(没有 Activity 、UI 线程或 HTTP 网络,只有一个 JSON 文件和标准输出输出),但这个概念可以很容易地迁移到 Android 系统,只需最少的努力.这是长度为 84047 的文件的输出:

Read: 0%
Read: 9%
Read: 19%
Read: 29%
Read: 38%
Read: 48%
Read: 58%
Read: 68%
Read: 77%
Read: 87%
Read: 97%
Read: 100%
Downloaded

关于android - 如何获取 JsonReader 字节来计算百分比,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41587185/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com