我正在構建一個應用程序,用於練習和學習,旨在從互聯網上下載文件。我相信我將來必須對其進行很多更改,但截至目前,我無法正確更新進度欄。當我點擊按鈕時,AsyncTask子類應該運行並獲取文件。當文件從互聯網上被讀取時,進度條應該被更新。問題在於有時進度條看起來立刻會立即更新,有時甚至會滯後很長一段時間,直到再次更新一次。我發現使用buffer.size()作爲publishProgress()的參數存在問題,但我不知道如何正確執行此操作。 onPostExecute()也需要很長時間才能運行。作爲一個小隊,我有一小段代碼,我註釋到使用rxjava來更新進度條。我正在考慮嘗試使用這樣的東西來取代onPostExecute()。這會是一個壞主意嗎?是「rxjava的正確用法?」這裏是我的MainActivity:android進度條沒有正確更新進度(onPostExecute()運行較晚)
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);
}
}
我道歉,如果我的問題似乎還不清楚。我所要求的基本上是如何更有效地執行與從互聯網閱讀相關的進度更新,並減少被調用的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());
}
嘗試從doInBackground方法返回的字符串。因此,您可以檢查onPostExecute中的狀態任務是否已完成。 –
你爲什麼不嘗試'在AsyncTask類中保護無效onProgressUpdate' –
@AshutoshSagar你的意思是我應該打電話onProgressUpdate?我沒有在我的AsyncTask中覆蓋它。我是否需要調用super.onProgressUpdate?或者我錯過了什麼? –