I am writing this application where I get live images from a tcp connection and I need to display them on an ImageViev.
What I am doing is calling the asynctask inside the button click. but it seem to create a number of background threads.
this is the code for the button click event
btnLive.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try
{
String name = ((Button)v).getText().toString();
if(name.equalsIgnoreCase("Live"))
{
DataOutputStream dos;
DataInputStream dis;
String reply;
if(config.conn.isConnected())
{
dos = new DataOutputStream(config.conn.getOutputStream());
dos.writeBytes("STREAM-LIVE-IMAGES");
dos.flush();
//dis = new DataInputStream(in);
in = config.conn.getInputStream();
while (true)
{
new myTask().execute(in);
}
}
}
}
catch(Exception ex)
{
Log.d("Live Button ", "Exception " + ex.getMessage() );
}
}
});
and this the code for the asyncTask
class myTask extends AsyncTask<InputStream, Integer, Bitmap> {
protected Bitmap doInBackground(InputStream...in)
{
Bitmap bmp = null;
try
{
//Do some none UI stuff here and return a value *result
byte[] rcvPacket = ReadJpegBinaryAndRemoveDelimiter(in[0]);
bmp = BitmapFactory.decodeByteArray(rcvPacket, 0, rcvPacket.length);
Log.d("Live Image Streaming ", "Recieved Images: " + rcvPacket.length + " " + bmp);
} catch (Exception e) {
e.printStackTrace();
}
return bmp;
}
while (true) {
new myTask().execute(in);
}
because you are executing AsyncTask in loop, in your case in infinite loop, it's not sounds very well, you need to change it.
You need to execute in outside of loop. You shouldn't, musn't do it.
Just call
new myTask().execute(in);
without loop.
I managed to sort it out with a background thread because asynctask wasnt the right option for my issue.
So I created a separate background thread and used a post runnable method on the imageview to update the UI.
Related
I am in the process of making a simple practice Morse code application.
I am trying to make an Image View flash between black and white in the SOS sequence based on Morse. When researching how to achieve this i realized i would have to do this on a separate thread in order to not block the UI thread.
The problem is that i am currently updating the Image View from outside of the UI thread which is stated to be a bad idea. At the moment i am trying to pass the Image View to the worker thread class that contains the logic for the screen flash.
I am new to multi-threading and i am pretty sure i am doing this completely backwards/incorrectly. Does anyone have an advice or ideas as of the best method to go about this?
new Thread(new Runnable() {
public void run() {
sf = new ScreenFlash("...---...", imgV);
sf.flashScreen();
}
}).start();
public ScreenFlash(String message, ImageView imgV){
this.message = message.replaceAll(".(?!$)", "$0 ");
this.imgV = imgV;
}
public void flashScreen() {
int offIntervalTime = 50;
char[] cArray = message.toCharArray();
for (int i = 0; i < cArray.length; i++) {
if (cArray[i] == '.') {
imgV.setBackgroundColor(Color.WHITE);
try {
Thread.sleep(50);
}catch(Exception e)
{
}
imgV.setBackgroundColor(Color.BLACK);
try {
Thread.sleep(offIntervalTime);
}catch(Exception e)
{
}
} else if(cArray[i] == ' ')
{
try{
Thread.sleep(100);
}catch(Exception e)
{
}
}
else {
try{
imgV.setBackgroundColor(Color.WHITE);
Thread.sleep(dash);
}catch(Exception e)
{
}
try{
imgV.setBackgroundColor(Color.BLACK);
Thread.sleep(offIntervalTime);
}catch(Exception e)
{
}
}
}
Take a look at the Handler class documentation and how to communicate with the UI thread from a background thread:
http://developer.android.com/training/multiple-threads/communicate-ui.html
You can update your imageView in onHandleMessage()
#Override
public void handleMessage(Message inputMessage) {
imageView.setBackgroundColor(android.R.color.white)
...
}
I have been trying to download videos from a url, I have implemented my downloading method in the doInBackground() of asynctask, but the doInBackground method is taking a lot of time to get called(5-10 mins), I am using another asyntask to download image in the activity from which I am directed to download video activity and its working fine. My onPreExecute method is being called on time, but after that doInBackground takes almost 5-7 minutes to start. I will be really grateful for any help provided.
Here is mycode
btnDownloadLQ.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0)
{
try
{
new DownloadVideoTask().execute(videoURL);
}
catch(Exception e)
{
Log.e("Vidit_TAG","I got an error",e);
}
}
});
private class DownloadVideoTask extends AsyncTask<String, String, String>
{
#SuppressWarnings("deprecation")
#Override
protected void onPreExecute() {
super.onPreExecute();
showDialog(DIALOG_DOWNLOAD_PROGRESS);
}
protected String doInBackground(String... urls)
{
int i=0;
try
{
URL url = new URL (urls[0]);
InputStream input = url.openStream();
try {
//The sdcard directory e.g. '/sdcard' can be used directly, or
//more safely abstracted with getExternalStorageDirectory()
String root = Environment.getExternalStorageDirectory().toString();
File storagePath = new File(root + "/vidit");
storagePath.mkdirs();
OutputStream output = new FileOutputStream (new File(storagePath,title+".mp4"));
try
{
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0)
{
output.write(buffer, 0, bytesRead);
}
}
catch(Exception e)
{
Log.e("Vidit_TAG","I got an error",e);
}
finally
{
output.close();
}
}
catch(Exception e)
{
Log.e("Vidit_TAG","I got an error",e);
}
finally
{
input.close();
//tvTitle.setText("Completed");
}
}
catch(Exception e)
{
Log.e("Vidit_TAG","I got an error",e);
}
return null;
}
#SuppressWarnings("deprecation")
#Override
protected void onPostExecute(String unused)
{
dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
alertbox(title);
}
}
make sure no other asyncTasks are running , by cancelling them if needed.
on most android versions , asyncTask runs on a single background thread , and should only run small tasks .
in case the task might take too long (or there are multiple tasks) , consider cancelling them or use an alternative approach (like using executeOnExecutor as described on the API ) .
Late Answer but surely helps
If you are using min API level >=11 try this
//new YourAsyncTask().execute(); -- replace this with following line
new YourAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //use this
I'm facing the same issue in spite of it didnot happen every time.
You could use the tradtional Thread for an alternative and handle the UI changes yourself
I'm not the best programmer, actually, I'm pretty bad :(
I need help with something thats driving my crazy. basically I have a tcpdump process, I want to extract the output and put it into a textview which is updated every few milliseconds, I've tried everything and just cant get it to work.
I don't get any errors and it seems to work in the background, but only displays chunks of text only after I go to the homescreen and return back into the app. however, it doesnt constantly update the textview, and sometimes hangs and crashes.
I've created a simple handler which can update the textview with plain text without problems, but then i faced major problems getting it to read the process.
Begin button
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.capture);
this.LiveTraffic = (TextView) findViewById(R.id.LiveTraffic);
this.CaptureText = (TextView) findViewById(R.id.CaptureText);
((TextView) findViewById(R.id.ipv4)).setText(getLocalIpv4Address());
((TextView) findViewById(R.id.ipv6)).setText(getLocalIpv6Address());
//Begin button
final Button startButton = (Button) findViewById(R.id.start);
startButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Now Capturing Packets", Toast.LENGTH_LONG).show();
try {
process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("/data/local/tcpdump -q\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
os.close();
inputStream = new DataInputStream(process.getInputStream());
Thread.sleep(1000);
Process process2 = Runtime.getRuntime().exec("ps tcpdump");
DataInputStream in = new DataInputStream(process2.getInputStream());
String temp = in.readLine();
temp = in.readLine();
temp = temp.replaceAll("^root *([0-9]*).*", "$1");
pid = Integer.parseInt(temp);
Log.e("MyTemp", "" + pid);
process2.destroy();
CaptureActivity.this.thisActivity.CaptureText.setText("Active");
} catch (Exception e) {
}
ListenThread thread = new ListenThread(new BufferedReader(new InputStreamReader(inputStream)));
thread.start();
}
});
}
ListenThread class
public class ListenThread extends Thread {
public ListenThread(BufferedReader reader) {
this.reader = reader;
}
private BufferedReader reader = null;
#Override
public void run() {
reader = new BufferedReader(new InputStreamReader(inputStream));
while (true) {
try {
CaptureActivity.this.thisActivity.CaptureText.setText("exec");
int a = 1;
String received = reader.readLine();
while (a == 1) {
CaptureActivity.this.thisActivity.LiveTraffic.append(received);
CaptureActivity.this.thisActivity.LiveTraffic.append("\n");
received = reader.readLine();
CaptureActivity.this.thisActivity.CaptureText.setText("in loop");
}
CaptureActivity.this.thisActivity.CaptureText.setText("out loop");
} catch (Exception e) {
Log.e("FSE", "", e);
}
}
}
}
I am not an android expert but I notice that:
you are running I/O operations in the UI thread - that will freeze your GUI until the I/O operation finishes ==> run them in a separate thread.
you update the UI from outside the UI thread in ListenThread, which can lead to unexpected results
You can read more about it in this tutorial (make sure you read the 2 examples as the first one is broken (on purpose)).
EDIT
In conclusion you should have something like this in your first piece of code:
startButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Now Capturing Packets", Toast.LENGTH_LONG).show();
new Thread(new Runnable() {
public void run() {
try {
process = Runtime.getRuntime().exec("su");
...
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("Active");
}
});
} catch (Exception e) {
}
ListenThread thread = new ListenThread(new BufferedReader(new InputStreamReader(inputStream)));
thread.start();
}
}).start();
}
});
and in the second:
while (true) {
try {
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("exec");
}
});
int a = 1;
String received = reader.readLine();
while (a == 1) {
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.LiveTraffic.append(received);
CaptureActivity.this.thisActivity.LiveTraffic.append("\n");
CaptureActivity.this.thisActivity.CaptureText.setText("in loop");
}
});
received = reader.readLine();
}
CaptureActivity.this.runOnUiThread(new Runnable() {
public void run() {
CaptureActivity.this.thisActivity.CaptureText.setText("out loop");
}
});
} catch (Exception e) {
Log.e("FSE", "", e);
}
}
That should solve the specific UI interaction issue. But there are other logic problems in your code which go beyond this question (for example the fact that you never test if you have reached the end of the file you are reading, the fact that while(a==1) is an infinite loop because you never change the value of a etc.).
I'm trying to write code to pull a server every second for updated messages. The messages then get displayed in a text view. If I do not change the text in the text view it runs fine. It will crash if I try to change the textview on the thread. IF i change it not on the thread works fine.
I'm assuming the thread cannot access the main threads memory? How can I set the text in the view with the text just loaded over the internet?
In the code below I have a thread that does a endless loop with a sleep. It calls a method called SendMessage. Send Message loads in text over the internet and at the end tries to update the View with it. It causes a exception when this happens.
code:
public class cChat extends cBase implements OnClickListener {
/** Called when the activity is first created. */
TextView mUsers;
TextView mComments;
int i=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat);
mUsers=( TextView) findViewById(R.id.viewusers);;
mComments=( TextView) findViewById(R.id.viewchats);;
Thread thread = new Thread()
{
#Override
public void run() {
try {
int t=0;
while(true)
{
SendMessage();
sleep(1000*5);
t++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
public void onClick(View v) {
} // end function
// send a uypdate message to chat server
// return reply in string
void SendMessage()
{
try {
URL url = new URL("http://50.63.66.138:1044/update");
System.out.println("make connection");
URLConnection conn = url.openConnection();
// set timeouts to 5 seconds
conn.setConnectTimeout(1000*5);
conn.setReadTimeout(5*1000);
conn.setDoOutput(true);
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// String line;
String strUsers=new String("");
String strComments=new String("");
String line=new String();
int state=0;
while ((line= rd.readLine() ) != null) {
switch(state){
case 0:
if ( line.contains("START USER"))
state=1;
if ( line.contains("START COMMENTS"))
state=2;
break;
case 1:
if ( line.contains("END USER"))
state=0;
else
{
strUsers+=line;
strUsers+="\n";
}
break;
case 2:
if ( line.contains("END COMMENTS"))
state=0;
else {
strComments+=line;
strComments+="\n";
}
break;
} // end switch
} // end loop
// the next line will cause a exception
mUsers.setText(strUsers);
mComments.setText(strComments);
} catch (Exception e) {
i++; // use this to see if it goes here in debugger
// System.out.println("exception");
// System.out.println(e.getMessage());
}
} // end methed
}
use runOnUiThread as
YOUR_CURRENT_ACTIVITY.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// the next line will cause a exception
mUsers.setText(strUsers);
mComments.setText(strComments);
//....YOUR UI ELEMENTS
}
});
EDIT :
see doc runOnUiThread
You can use a handler to post tasks (Runnables) to the UI/Main Thread:
private Handler handler = new Handler();
//...
Thread thread = new Thread()
{
#Override
public void run() {
try {
int t=0;
while(true)
{
handler.post(new Runnable() {
#Override
public void run() {
SendMessage();
}
});
sleep(1000*5);
t++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
You can't touch an UI widget from a thread different than the one used to create it (the UI thread). But if you have a reference to the Activity, you can simply do:
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
mUsers.setText(strUsers);
mComments.setText(strComments);
}
});
which would require strUsers to be accessible by the anonymous class. For that you can simply do:
final String finalUseres = strUsers;
and use finalUsers within run().
Try using a Service to continuously pull/send data to server. This will reduce the load on your UI-Thread.
the Andoid UI toolkit is not thread-safe. So, you
must not manipulate your UI from a worker thread
To fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
you can also use AsyncTask.
see this tutorial on process and threads in android.
I am running remote audio-file-fetching and audio file playback operations in a background thread using AsyncTask. A Cancellable progress bar is shown for the time the fetch operation runs.
I want to cancel/abort the AsyncTask run when the user cancels (decides against) the operation. What is the ideal way to handle such a case?
Just discovered that AlertDialogs's boolean cancel(...); I've been using everywhere actually does nothing. Great.
So...
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
private final ProgressDialog progressDialog;
public MyTask(Context ctx) {
progressDialog = gimmeOne(ctx);
progressDialog.setCancelable(true);
progressDialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true);
}
});
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
while (running) {
// does the hard work
}
return null;
}
// ...
}
If you're doing computations:
You have to check isCancelled() periodically.
If you're doing a HTTP request:
Save the instance of your HttpGet or HttpPost somewhere (eg. a public field).
After calling cancel, call request.abort(). This will cause IOException be thrown inside your doInBackground.
In my case, I had a connector class which I used in various AsyncTasks. To keep it simple, I added a new abortAllRequests method to that class and called this method directly after calling cancel.
The thing is that AsyncTask.cancel() call only calls the onCancel function in your task. This is where you want to handle the cancel request.
Here is a small task I use to trigger an update method
private class UpdateTask extends AsyncTask<Void, Void, Void> {
private boolean running = true;
#Override
protected void onCancelled() {
running = false;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
onUpdate();
}
#Override
protected Void doInBackground(Void... params) {
while(running) {
publishProgress();
}
return null;
}
}
Simple: don't use an AsyncTask. AsyncTask is designed for short operations that end quickly (tens of seconds) and therefore do not need to be canceled. "Audio file playback" does not qualify. You don't even need a background thread for ordinary audio file playback.
The only way to do it is by checking the value of the isCancelled() method and stopping playback when it returns true.
This is how I write my AsyncTask
the key point is add Thread.sleep(1);
#Override protected Integer doInBackground(String... params) {
Log.d(TAG, PRE + "url:" + params[0]);
Log.d(TAG, PRE + "file name:" + params[1]);
downloadPath = params[1];
int returnCode = SUCCESS;
FileOutputStream fos = null;
try {
URL url = new URL(params[0]);
File file = new File(params[1]);
fos = new FileOutputStream(file);
long startTime = System.currentTimeMillis();
URLConnection ucon = url.openConnection();
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
byte[] data = new byte[10240];
int nFinishSize = 0;
while( bis.read(data, 0, 10240) != -1){
fos.write(data, 0, 10240);
nFinishSize += 10240;
**Thread.sleep( 1 ); // this make cancel method work**
this.publishProgress(nFinishSize);
}
data = null;
Log.d(TAG, "download ready in"
+ ((System.currentTimeMillis() - startTime) / 1000)
+ " sec");
} catch (IOException e) {
Log.d(TAG, PRE + "Error: " + e);
returnCode = FAIL;
} catch (Exception e){
e.printStackTrace();
} finally{
try {
if(fos != null)
fos.close();
} catch (IOException e) {
Log.d(TAG, PRE + "Error: " + e);
e.printStackTrace();
}
}
return returnCode;
}
Our global AsyncTask class variable
LongOperation LongOperationOdeme = new LongOperation();
And KEYCODE_BACK action which interrupt AsyncTask
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
LongOperationOdeme.cancel(true);
}
return super.onKeyDown(keyCode, event);
}
It works for me.
I don't like to force interrupt my async tasks with cancel(true) unnecessarily because they may have resources to be freed, such as closing sockets or file streams, writing data to the local database etc. On the other hand, I have faced situations in which the async task refuses to finish itself part of the time, for example sometimes when the main activity is being closed and I request the async task to finish from inside the activity's onPause() method. So it's not a matter of simply calling running = false. I have to go for a mixed solution: both call running = false, then giving the async task a few milliseconds to finish, and then call either cancel(false) or cancel(true).
if (backgroundTask != null) {
backgroundTask.requestTermination();
try {
Thread.sleep((int)(0.5 * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (backgroundTask.getStatus() != AsyncTask.Status.FINISHED) {
backgroundTask.cancel(false);
}
backgroundTask = null;
}
As a side result, after doInBackground() finishes, sometimes the onCancelled() method is called, and sometimes onPostExecute(). But at least the async task termination is guaranteed.
With reference to Yanchenko's answer on 29 April '10:
Using a 'while(running)' approach is neat when your code under 'doInBackground' has to be executed multiple times during every execution of the AsyncTask. If your code under 'doInBackground' has to be executed only once per execution of the AsyncTask, wrapping all your code under 'doInBackground' in a 'while(running)' loop will not stop the background code (background thread) from running when the AsyncTask itself is cancelled, because the 'while(running)' condition will only be evaluated once all the code inside the while loop has been executed at least once. You should thus either
(a.) break up your code under 'doInBackground' into multiple 'while(running)' blocks or
(b.) perform numerous 'isCancelled' checks throughout your 'doInBackground' code, as explained under "Cancelling a task" at https://developer.android.com/reference/android/os/AsyncTask.html.
For option (a.) one can thus modify Yanchenko's answer as follows:
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
//...
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
// does the hard work
while (running) {
// part 1 of the hard work
}
while (running) {
// part 2 of the hard work
}
// ...
while (running) {
// part x of the hard work
}
return null;
}
// ...
For option (b.) your code in 'doInBackground' will look something like this:
public class MyTask extends AsyncTask<Void, Void, Void> {
//...
#Override
protected Void doInBackground(Void... params) {
// part 1 of the hard work
// ...
if (isCancelled()) {return null;}
// part 2 of the hard work
// ...
if (isCancelled()) {return null;}
// ...
// part x of the hard work
// ...
if (isCancelled()) {return null;}
}
// ...