[英]android progress bar not updating progress correctly (onPostExecute() runs late)
我正在構建一個用於練習和學習的應用程序,旨在從互聯網上下載文件。 我確定將來我將不得不對其進行很多更改,但是截至目前,我無法使進度條正確更新。 當我單擊按鈕時,應該運行AsyncTask子類並獲取文件。 從互聯網讀取文件時,進度條應該會更新。 問題在於進度條有時似乎一次全部立即更新,有時進度條滯后很長時間保持空白直到再次更新,一次全部更新。 我看到使用buffer.size()作為publishProgress()的參數存在問題,但是我不確定如何正確執行此操作。 onPostExecute()也需要很長時間才能運行。 作為附帶的問題,我有一小段代碼被我注釋掉,它使用rxjava更新進度條。 我正在考慮嘗試使用類似這樣的方法替換onPostExecute()。 那是個壞主意嗎? 是“ rxjava的正確用法”嗎? 這是我的MainActivity:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MAIN";
private static final String startURL = "https://www.google.com";
private static final int REQUEST_CODE_EXTERNAL = 0;
private Button runButton;
private EditText urlSpecBox;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//request for permission to write to storage here
if(ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, (new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}), REQUEST_CODE_EXTERNAL);
}
progressBar = (ProgressBar) findViewById(R.id.progroessBar);
progressBar.setMax(100);
runButton = (Button) findViewById(R.id.dwnldButton);
runButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try{
progressBar.setVisibility(View.VISIBLE);
progressBar.setProgress(0);
new AsyncDownload(new URL(startURL), progressBar).execute();
}catch (MalformedURLException me){
Log.e(TAG, "error with url", me);
}
}
});
urlSpecBox = (EditText) findViewById(R.id.urlSpecBox);
}
}
和我的asynctask子類:
public class AsyncDownload extends AsyncTask<Void, Integer, Void>{
private static final String TAG = "AsyncDownload";
private static final String STORAGE_LOCATION = "/sdcard/"; //android directory picker is needed
private URL url;
private ProgressBar mProgessBar;
//private ArrayList<Byte> bytes = new ArrayList<>();
public AsyncDownload(URL url, ProgressBar progressBar){
mProgessBar = progressBar;
this.url = url;
}
@Override
protected void onProgressUpdate(Integer... progress){
mProgessBar.setProgress(progress[0]);
}
@Override
protected Void doInBackground(Void... params){
try{
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int c;
while ((c = in.read()) != -1){
buffer.write(c);
publishProgress(buffer.size());
}
Log.i(TAG, "response received");
Random rand = new Random(4L);
String temp = String.valueOf(rand.nextInt());
String finalLocation = STORAGE_LOCATION + temp;
File file = new File(finalLocation);
file.getParentFile().mkdirs();
Log.i(TAG, file.getName());
FileOutputStream fOut = new FileOutputStream(file);
fOut.write(buffer.toByteArray());
buffer.close();
fOut.flush();
fOut.close();
FileInputStream fIn = new FileInputStream(finalLocation);
String reRead = new String();
int a;
while ((a = fIn.read()) != -1){
reRead += a;
}
Log.i(TAG, "reRead" + reRead);
//this section is for automatic file naming
/*Random rand = new Random(5L);
String fileNumber = String.valueOf(rand.nextInt());
StringBuilder sb = new StringBuilder();
sb.append(fileNumber).append("download"); //definitely needs work
Log.i(TAG, sb.toString());*/
//FileOutputStream fOut = new FileOutputStream()
}catch (IOException ioe){
Log.e(TAG, "network error" + ioe.toString(), ioe);
}
/*rx.Observable.just(0) //is it correct to use rxjava this way?
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<Integer>() {
@Override
public void call(Integer integer) {
mProgessBar.setProgress(integer);
mProgessBar.setVisibility(View.VISIBLE);
}
}
);*/
return null;
}
@Override
protected void onPostExecute(Void result){ // METHOD IS NEVER CALLED
super.onPostExecute(result);
Log.i(TAG, "onPostExecute called! - Task Completed!");
mProgessBar.setProgress(0);
mProgessBar.setVisibility(View.GONE);
}
}
如果我的問題不清楚,我深表歉意。 我要問的基本上是我如何才能更有效地執行與從Internet讀取相關的進度更新,並減少doInBackground()被調用和onPostExecute()之間的延遲。
編輯我的代碼:
int c;
int progress = 0;
int count = buffer.size();
int fileSize = connection.getContentLength();
while ((c = in.read()) != -1){
buffer.write(c);
try{
Thread.sleep(TimeUnit.MILLISECONDS.toMillis(100L));
}catch (InterruptedException ie){
Log.e(TAG, "thread interrupted", ie);
}finally {
if (count > 0){
publishProgress((int) ((progress+=count)*100/fileSize));
}
}
//publishProgress(buffer.size());
}
您之所以會滯后,是因為您在一個循環中進行了公共進度,這會使主線程多次調用它。 我們在這里有一些解決方案:
請延遲使用Thread.sleep。 至少1億。
試試{Thread.sleep(100); } catch(InterruptedException e){}最后{如果(fileLength> 0){this.publishProgress((int)((progress + = count)* 100 / fileLength)); }}
與之前的百分比相比增加1%只是公共進度。
更新代碼:不需要使用緩沖區
FileOutputStream fOut = new FileOutputStream(file); FileInputStream fIn = new FileInputStream(finalLocation); byte data[] = new byte[4096]; long progress = 0; int count; int fileSize = connection.getContentLength(); while ((c = in.read()) != -1){ //we should write the data before publish progress fOut.write(data, 0, count) try{ Thread.sleep(100); }catch (InterruptedException ie){ Log.e(TAG, "thread interrupted", ie); }finally { if (fileSize > 0){ publishProgress((int) ((progress+=count)*100/fileSize)); } } }
要么
if (fileSize > 0) {
currentProgress = ((progress += count) * 100 / fileSize);
// Publish only on increments of 1%
if (currentProgress >= previousProgress + 1) {
this.publishProgress(currentProgress);
previousProgress = currentProgress;
}
}
在您的AsyncDownload類中使用它
@Override
protected void onProgressUpdate(Integer... values) {
progressBar.setProgress(values[0]);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.