2017-07-13 4 views
0

Ich bin eine Anwendung zum Üben und Lernen, die Dateien aus dem Internet herunterladen soll. Ich bin mir sicher, dass ich in Zukunft viele Änderungen daran vornehmen muss, aber ab jetzt habe ich Probleme, den Fortschrittsbalken korrekt zu aktualisieren. Wenn ich auf die Schaltfläche klicke, sollte eine AsyncTask-Unterklasse ausgeführt werden und die Datei erhalten. Der Fortschrittsbalken sollte aktualisiert werden, wenn die Datei aus dem Internet gelesen wird. Das Problem ist, dass manchmal die Fortschrittsleiste scheinbar sofort auf einmal aktualisiert wird, und manchmal bleibt sie lange Zeit leer, bis sie wieder auf einmal aktualisiert wird. Ich sehe, dass es ein Problem mit meiner Verwendung von buffer.size() als Argument für publishProgress() gibt, aber ich bin mir nicht sicher, wie ich das richtig machen kann. onPostExecute() benötigt ebenfalls sehr viel Zeit zum Ausführen. Als Nebenfrage habe ich einen kleinen Codeabschnitt, den ich auskommentierte, der rxjava verwendet, um den Fortschrittsbalken zu aktualisieren. Ich überlegte, ob ich versuchen sollte, so etwas zu verwenden, um onPostExecute() zu ersetzen. Wäre das eine schlechte Idee? ist das eine "richtige Verwendung von rxjava?" hier ist mein MainActivity:Android Fortschrittsbalken Fortschritt nicht korrekt aktualisieren (onPostExecute() läuft spät)

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); 

} 
} 

und meine AsyncTask Unterklasse:

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); 
} 

} 

Ich entschuldige mich, wenn meine Frage nicht klar zu sein scheint. Was ich frage, ist im Grunde, wie ich das Fortschritts-Update im Zusammenhang mit dem Lesen aus dem Internet effizienter durchführen und die Verzögerung zwischen dem Aufruf von doInBackground() und dem Aufruf von onPostExecute() verringern kann.

eine Bearbeitung auf meinem Code:

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()); 
     } 
+0

Versuchen Zeichenfolge aus doInBackground Methode zurück. So können Sie den Status in onPostExecute überprüfen, ob die Aufgabe abgeschlossen wurde oder nicht. –

+0

Warum versuchst du nicht 'protected void onProgressUpdate' in AsyncTask Klasse –

+0

@AshutoshSagar meinst du, dass ich onProgressUpdate aufrufen soll? Ich habe es in meiner AsyncTask überschrieben. Muss ich super.onProgressUpdate aufrufen? Oder fehlt mir etwas? –

Antwort

1

Sie bekam Verzögerung, weil Sie in einer Schleife öffentlichen Fortschritte, wird es Haupt-Thread nennen viele Zeit. Wir haben hier eine Lösung:

  1. Bitte verzögern Sie die Verwendung Thread.sleep. mindestens 100 Mil.

    versuchen { Thread.sleep (100); } catch (InterruptedException e) { } schließlich { if (fileLength> 0) { this.publishProgress ((int) ((Fortschritt + = Anzahl) * 100/fileLength)); } }

  2. Nur öffentlichen Fortschritt, wenn es 1% im Vergleich zu vorherigen Prozent erhöhen.

  3. Code Update: Dont müssen Puffer verwenden

    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)); 
         } 
        } 
    } 
    

oder

if (fileSize > 0) { 
    currentProgress = ((progress += count) * 100/fileSize); 
    // Publish only on increments of 1% 
    if (currentProgress >= previousProgress + 1) { 
     this.publishProgress(currentProgress); 
     previousProgress = currentProgress; 
    } 

} 
+0

Ich verstehe gerade nicht, was ich für Fortschritt und Zählung verwenden sollte. Ich versuche den Fortschritt als int auf 0 initialisiert, aber ich bin unklar, wo man zählen kann. Muss ich anstelle von while eine for-Schleife verwenden? –

+0

Ich habe eine Änderung an meinem Code vorgenommen, die ich versuche, Ihrem Rat zu folgen. scheint, ich mache es falsch, obwohl die Verzögerung zugenommen hat. –

+0

ich aktualisiere meine antwort – GiaLe

0

Verwenden Sie diese in Ihrer AsyncDownload Klasse

@Override 
     protected void onProgressUpdate(Integer... values) { 
      progressBar.setProgress(values[0]); 
     } 
+0

'@Override protected void onProgressUpdate (Integer ... progress) { mProgessBar.setProgress prüfen (Fortschritt [0]); } 'das ist meine Verwendung. Ist das korrekt? –

Verwandte Themen