Reputation: 82
I am using AsyncTask
for downloading video file I am update views inside the AsyncTask
but exception arises "Only the original thread that created a view hierarchy can touch its views". Here is my sample code. Please check it and suggest me where I need correction.
The exception arises at these lines.
tvPercent.setText((int)per + "%");
tvSpeed.setText(networkSpeed+"kbps");
AsyncTask Class
public class DownloadFileFromURL extends AsyncTask<String, String, String> {
ProgressBar ProgBar;
TextView tvSpeed;
TextView tvPercent;
int downloadedSize = 0;
int totalSize = 0;
private long networkSpeed;
private long previousTime;
private long totalTime;
// public DownloadFileFromURL(ProgressBar pb)
// {
// ProgBar = pb;
//
// }
public DownloadFileFromURL(ProgressBar pb, TextView speed, TextView per)
{
ProgBar = pb;
tvSpeed = speed;
tvPercent = per;
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
ProgBar.setProgress(0);
//ProgBar.setMax(100);
previousTime = System.currentTimeMillis();
}
@Override
protected String doInBackground(String... videoURL)
{
try
{
URL url = new URL(videoURL[0]);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
//connect
urlConnection.connect();
File file = getOutputMediaFile(videoURL[0]);
FileOutputStream fileOutput = new FileOutputStream(file);
//Stream used for reading the data from the internet
InputStream inputStream = urlConnection.getInputStream();
//this is the total size of the file which we are downloading
totalSize = urlConnection.getContentLength();
Log.e("Download", ""+totalSize);
ProgBar.setMax(totalSize);
//create a buffer...
byte[] buffer = new byte[1024];
int bufferLength = 0;
while ( (bufferLength = inputStream.read(buffer)) > 0 )
{
fileOutput.write(buffer, 0, bufferLength);
downloadedSize += bufferLength;
// update the progressbar //
ProgBar.setProgress(downloadedSize);
float per = ((float)downloadedSize/totalSize) * 100;
// update the progress in percentage //
tvPercent.setText((int)per + "%");
totalTime = System.currentTimeMillis() - previousTime;
networkSpeed = downloadedSize / totalTime;
// update network speed //
tvSpeed.setText(networkSpeed+"kbps");
}
//close the output stream when complete //
fileOutput.close();
downloadedSize = 0;
totalSize = 0;
}
catch (final MalformedURLException e)
{
e.printStackTrace();
}
catch (final IOException e)
{
e.printStackTrace();
}
catch (final Exception e)
{
e.printStackTrace();
}
return null;
}
protected void onProgressUpdate(String... progress)
{
// setting progress percentage
//ProgBar.setProgress(Integer.parseInt(progress[0]));
}
@Override
protected void onPostExecute(String file_url)
{
}
}
Upvotes: 0
Views: 945
Reputation: 36
AsyncTask does its main work(in doInBackground method) on a separate thread, but only the main thread can access the user interface. Code in doInBackground can not access the user interface.
The methodes onPreExecute, onProgressUpdate, onPostExecute is invoked on the main thread. Do any access to the user interface in these methods.
Call publishProgress in doInBackground to invoke onProgressUpdate on the main thread.
Read all about AsyncTask here.
Upvotes: 0
Reputation: 1207
I Fetched same problem many time then finally i got final solution for this problem. remove all code that that change xml or update layout xml file from background method do it on post execute method.
Upvotes: 0
Reputation: 1860
You can update UI only from the main thread. Move tvPercent.setText((int)per + "%");
to onProgressUpdate
and call publishProgress(.)
in doInBackground
whenever you want to update the text.
Upvotes: 2