Пытаюсь получить размер загружаемого файла, но получаю ошибку

private class DownloadLargeFileTask extends AsyncTask<Void, Void, Void> 
{
    private final ProgressDialog dialog;

    public DownloadLargeFileTask(ProgressDialog dialog) {
         this.dialog = dialog;
    }

    protected void onPreExecute() {
        dialog.show();
    }


    protected void onPostExecute(Void unused) {
        dialog.dismiss();
    }

    @Override
    protected Void doInBackground(Void... arg0) {
        download();
        return null;
    }
}

private void download ()
{
    try 
    {
        long startTime = System.currentTimeMillis();

        URL u = new URL("http://mds.podfm.ru/188/download/040_Sergejj_Palijj_-_Karantin_CHast_2.mp3");
        HttpURLConnection c = (HttpURLConnection) u.openConnection();

        c.setRequestMethod("GET");
        c.setDoOutput(true);
        c.connect();
        FileOutputStream f = new FileOutputStream(new File("/sdcard/","my.mp3"));

        InputStream in = c.getInputStream();

        byte[] buffer = new byte[1024];
        int len1 = 0;
        int downloadedSize = 0;
        while ( (len1 = in.read(buffer)) != -1 ) 
        {
          f.write(buffer,0, len1);
          downloadedSize += len1; 
          ReturnDownloadedBytes(downloadedSize);
        }
        f.close();
        Log.d("ImageManager", "download ready in" + ((System.currentTimeMillis() - startTime) / 1000) + " sec");
    }
    catch (IOException e)
    {
        Log.d("ImageManager", "Error" + ((System.currentTimeMillis()) / 1000) + e + " sec");
    }
}

private void ReturnDownloadedBytes(int size)
{
    text.setText(String.valueOf(size));

}

Ошибка гласит: только исходный поток, создавший иерархию представлений, может касаться своих представлений. я думаю, это означает, что я создаю текстовое представление из одного терада и пытаюсь получить доступ из другого (AsyncTask), но как его получить? Спасибо

EDIT
вот весь код. но даже если я отправлю publishProgress(downloadedSize) int value = 10, он всегда выводит text.setText(String.valueOf(progress)); разные значения, такие как [Ljava.lang.float;@43ed62f78

public class list extends Activity {

private TextView text;



@Override
public void onCreate(Bundle icicle)
{
    super.onCreate(icicle);
    setContentView(R.layout.main);

    text = (TextView)findViewById(R.id.result);
}

public void selfDestruct(View view) {

    ProgressDialog dialog = new ProgressDialog(this);
    dialog.setMessage("????????. ?????...");
    new DownloadLargeFileTask(dialog).execute();

}


private class DownloadLargeFileTask extends AsyncTask<Void, Integer, Void> 
{
    private final ProgressDialog dialog;

    public DownloadLargeFileTask(ProgressDialog dialog) {
         this.dialog = dialog;
    }

    protected void onPreExecute() {
        dialog.show();
    }


    protected void onPostExecute(Void unused) {
        dialog.dismiss();
    }

    protected void onProgressUpdate(Integer...progress) {

        text.setText(String.valueOf(progress));

    }

    @Override
    protected Void doInBackground(Void... arg0) {
        try 
        {
            long startTime = System.currentTimeMillis();

            URL u = new URL("http://mds.podfm.ru/188/download/040_Sergejj_Palijj_-_Karantin_CHast_2.mp3");
            HttpURLConnection c = (HttpURLConnection) u.openConnection();

            c.setRequestMethod("GET");
            c.setDoOutput(true);
            c.connect();
            FileOutputStream f = new FileOutputStream(new File("/sdcard/","my.mp3"));

            InputStream in = c.getInputStream();

            byte[] buffer = new byte[1024];
            int len1 = 0;
            int downloadedSize = 10;
            while ( (len1 = in.read(buffer)) != -1 ) 
            {
              f.write(buffer,0, len1);
              //downloadedSize += len1; 
              **publishProgress(downloadedSize);**
            }
            f.close();
            Log.d("ImageManager", "download ready in" + ((System.currentTimeMillis() - startTime) / 1000) + " sec");
        }
        catch (IOException e)
        {
            Log.d("ImageManager", "Error" + ((System.currentTimeMillis()) / 1000) + e + " sec");
        }
        return null;
    }
}

person SERG    schedule 12.03.2011    source источник


Ответы (2)


Вы правы в оценке ошибки. Я предполагаю, что text — это объект TextView, определенный в вашем Activity, и поэтому он создается в потоке пользовательского интерфейса. Код, который выполняется в doInBackground(), выполняется в отдельном потоке. Только поток пользовательского интерфейса может выполнять обновления элементов пользовательского интерфейса, поэтому при попытке вызвать setText вы получите сообщение об ошибке, о котором сообщали.

Abhinav также прав в том, как решить проблему, поскольку AsyncTask имеет метод, который вы можете вызвать для отправки обновлений из фонового потока в поток пользовательского интерфейса: publishProgress, который вызывает onProgressUpdate().

Добавьте этот метод в свой AsyncTask:

@Override
protected void onProgressUpdate(Integer... integer){
    text.setText(integer[0].toString());
}

И меняем цикл while на download():

while ( (len1 = in.read(buffer)) != -1 ) 
{
  f.write(buffer,0, len1);
  downloadedSize += len1; 
  publishProgress(downloadedSize);
}
person dave.c    schedule 12.03.2011
comment
Можете ли вы объяснить мне, что означает URL, Integer, Long в этом частном классе DownloadFilesTask extends AsyncTask‹URL, Integer, Long› и в чем разница в порядке этих параметров/. Спасибо - person SERG; 12.03.2011
comment
и когда я вызываю text.setText (String.valueOf (прогресс)); в результате я получаю в TextView что-то вроде [Ljava.lang.float; @43ed62f78 - что это значит? - person SERG; 12.03.2011
comment
@SERG проверьте документацию, это Params, Progress и Result. Мне нужно увидеть больше вашего кода, чтобы диагностировать другую проблему. - person dave.c; 12.03.2011
comment
@SERG Пожалуйста, не публикуйте новый вопрос в качестве ответа на существующий вопрос. Тем не менее, сравнив мой код выше с вашим, вы можете видеть, что параметр onProgressUpdate() представляет собой массив значений, поэтому я использую integer[0].toString() для получения желаемого значения. Когда вы используете String.valueOf(progress), вы просто указываете место в памяти, так как progress — это массив. Пожалуйста, используйте подход, который я предоставил в своем ответе. - person dave.c; 13.03.2011

Вы можете изменить пользовательский интерфейс, опубликовав ход выполнения в потоке пользовательского интерфейса. Вызовите publishProgress из doInBackground. Это вызовет onProgressUpdate в вашей AsyncTask, откуда вы можете обновить пользовательский интерфейс.

Вам нужно будет определить onProgressUpdate в вашей AsyncTask. http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate(Progress...)

person Abhinav    schedule 12.03.2011