INTRODUCTION
I have an activity that processes some functions. Inside this activity, the main process is one thread that makes the processing of these functions.When the processing is done, it should call to another activity to start another diferent process.
This is my thread inside the main activity:
CODE
private static void DetectionThread (byte[] data, int width, int height, final Context context) {
mData = data;
mWidth = width;
mHeight = height;
mThread = new Thread() {
#Override
public void run() {
try {
//MAKES THE PROCESSING
//If it's right, continues to next code...
MotionDetectionActivity.gameStarted = true;
gameLaunched = true;
return;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
processing.set(false);
/*HERE MUST INIT THE ACTIVITY WITH INTENT*/
if (MotionDetectionActivity.gameStarted == true && gameLaunched == true) {
gameLaunched = false;
Intent gameIntent = new Intent(context, GameActivity.class);
context.startActivity(gameIntent);
}
processing.set(false);
}
}
};
if (MotionDetectionActivity.gameStarted == false) {
mThread.start();
}
}
QUESTION
Well, the thing is that i'm not getting the desired result. When initializing the GameActivity, it is not showing this activity's layout, and there are some functionalities that are not initialized, f.e. I do this to initialize the TTS:
private static TextToSpeech tts;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
tts = new TextToSpeech(this, this);
//Iniside main method
tts.speak("Initializing...", TextToSpeech.QUEUE_ADD, null);
The thing is that it doesn't talk.
Use AsyncTask instead of Thread, and call the another activity in the onPostExecute method
public class MyAsync extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//start the next activity here
}
#Override
protected Void doInBackground(Void... params) {
//your task goes here
return null;
}
}
Related
I have sample code which very simply does some heavy work and sends a message to a handler to update the UIThread. My concern is with the handler reference i am passing to the constructor. If my activity gets destroyed while the asncTask is still running will the handler reference not be null ?
public class SomeActivity extends Activity
{
private static final int UPDATE_BUTTON_TEXT = 1;
private static final SomeActivity me = null;
private static Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (me == null) return;
switch (msg.what) {
case UPDATE_BUTTON_TEXT:
Button btn = (Button) me.findViewById(R.id.someButton);
btn.setText((String) msg.obj);
}
}
};
private View.OnClickListener onClickListener = new View.OnClickListener() {
public void onClick(View view) {
new SomeLongRunningTask().execute();
}
};
private static class SomeLongRunningTask extends AsyncTask<Void, Void, Boolean> {
private Handler handler;
public SomeLongRunningTask(Handler handler) {
this.handler = handler;
}
#Override
protected Boolean doInBackground(Void... voids) {
try {
Thread.sleep(30000); // replace with some background logic
} catch (InterruptedException e) {}
return true;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
//can the handler be null here if activity is destroyed ????
Message msg = handler.obtainMessage(UPDATE_BUTTON_TEXT);
msg.obj = "success"
handler.sendMessage(msg);
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button someButton = (Button) findViewById(R.id.someButton);
someButton.setOnClickListener(onClickListener);
}
#Override
protected void onStart() {
super.onStart();
me = this;
}
#Override
protected void onStop() {
me = null;
super.onStop();
}
}
Yes, the reference of the handler is going to be retained in memory until it has a reference count > 0.
I think you should use AsyncTask().onProgressUpdate for updating progress on UI, which does what you're trying to do.
EDIT
If you're updating ui in onPostExecute then you don't need to use onProgressUpdate(my apologies).
Just use an interface as a callback function like below:
private interface Callback {
void updateUI(String value);
}
private static class SomeLongRunningTask extends AsyncTask<Void, String, Boolean> {
private Callback mCallback;
public SomeLongRunningTask(Callback callback) {
mCallback = callback;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
mCallback.updateUI("success");
}
}
// somewhere else...
Callback callback = new Callback() {
#Override
public void updateUI(String value) {
Button btn = (Button) me.findViewById(R.id.someButton);
btn.setText((String) msg.obj);
}
};
new SomeLongRunningTask(callback).execute();
Also it doesn't seem right to have a handler instance as a static variable. It will last until the class is unloaded.
As a rule, whenever I write an AsyncTask subclass, I use a pattern like this:
private WeakReference<Callback> mCallbackRef;
public MyAsyncTask(Callback callback) {
mCallbackRef = new WeakReference<>(callback);
}
#Override
protected void onPostExecute(Boolean aBoolean) {
if (mCallbackRef != null) {
Callback callback = mCallbackRef.get();
if (callback != null) {
callback.updateUI("success");
}
}
}
I'm having some trouble with an AsyncTask subclass.
I have a main activity as below that displays a button and a number that counts up on the screen. Clicking the button launches an Edit activity where a number can be entered.
The number displayed on the Main activity should update with the timer which it does but the trouble I'm having is that I can't stop the timer. It should stop when entering the Edit activity and returning from it as well, as well as restart with the a new value too but it doesn't, the timer is always running with the first entered value, it never stops, even when I leave the program and return to the home screen.
I've looked at posts here such as Can't cancel Async task in android but they all just mention checking for isCancelled() which I'm doing. Can anyone see/explain why I can't stop this AsyncTask ?
public class MainActivity extends Activity {
#Override
UpdateTimer ut;
TextView tvn;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onResume() {
super.onResume();
tvn = (TextView) findViewById(R.id.numDisplay);
if(ut != null )//&& ut.getStatus() == AsyncTask.Status.RUNNING) {
ut.cancel(true);
ut.cancelled = true;
Log.d("-----M_r","called cancel: "+ut.isCancelled()+" "+cancelled);
}
if (updateRequired) {
ut = new UpdateTimer();
ut.execute(number);
updateRequired = false;
}
}
public void onEditButtonPressed(View caller) {
// kill any running timer
if(ut != null )
{
ut.cancel(true);
ut.cancelled = true;
}
// start the edit screen
Intent e_intent = new Intent(this, EditActivity.class);
startActivity(e_intent);
}
private void updateScreen(long number) {
// update screen with current values
tvn.setText("" + number);
}
private class UpdateTimer extends AsyncTask<Long, Long, Integer> {
long number;
public boolean cancelled;
#Override
protected Integer doInBackground(Long... params) {
number = params[0];
cancelled = false;
while(true) {
number += 1;
//sleep for 1 second
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// tell this AsyncTask to update the time on screen
publishProgress(number);
// check if timer needs to stop
if (isCancelled()) break;
if(cancelled) break;
}
return null;
}
protected void onProgressUpdate(Long... progress) {
Log.d("-----M_ut","updated: "+number+" "+this.isCancelled()+" "+cancelled);
updateScreen(progress[0]);
}
protected void onCancelled(Integer result) {
cancelled = true;
Log.d("-----M_ut","-- cancelled called: "+this.isCancelled());
}
}
protected void onStop()
{
super.onStop();
// kill any running timer
if(ut != null) {
ut.cancel(true);
}
}
}
Try this...
remove the variable..cancelled and change to this..
#Override
protected void onCancelled() {
super.onCancelled();
}
call the super.onCancelled instead..
And in the doInBackground check
if (isCancelled()) {
break;
}
Try calling from your activity ut.cancel(true);
Hope it works:)
private YourAsyncTask ut;
declare your asyncTask in your activity.
ut = new YourAsyncTask().execute();
instantiate it like this.
ut.cancel(true);
kill/cancel it like this.
i want to increment a progress dialog from a thread inside a service, i have really hard time doing that, this is my code please help me.
I tried many different ways including asyncTask (I had problem with context)
and tried with static functions but its not working properly,
I pretty new with android please explain me the problem here.
the activity
public class MainActivity extends Activity {
ProgressDialog progressBar;
private void showProgrssBar() {
progressBar.show();
}
private void dismissProgressBar() {
progressBar.dismiss();
}
private void increaseProgressBar(int total) {
progressBar.incrementProgressBy(total);
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createProgressBarDialog();
Intent n = new Intent(this, myService.class);
startService(n);
}
private void createProgressBarDialog()
{
progressBar = new ProgressDialog(this);
progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressBar.setMax(200);
progressBar.setMessage("Recieving bluetooth data");
progressBar.setCanceledOnTouchOutside(false);
}
the service:
public class myService extends Service
{
private myThread myThread;
Handler handler = new Handler()
{
#Override
public void handleMessage(android.os.Message msg)
{
int total = msg.getData().getInt("total");
if (total == -1)
{
dismissProgressBar();
}
else if (total == 0)
{
showProgrssBar();
}
else
{
increaseProgressBar(total);
}
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
myThread = new myThread(handler);
myThread.start();
return START_STICKY;
}
the thread
class myThread extends Thread
{
Handler h;
int numOfLinesToRead = 220;
int line = 0;
public myThread(Handler h)
{
this.h = h;
}
private void increaseProgressBarOnActivity(int i_MsgType)
{
Message msg = h.obtainMessage();
Bundle b = new Bundle();
b.putInt("total", i_MsgType);
msg.setData(b);
h.sendMessage(msg);
}
#Override
public void run() {
super.run();
int increase;
try
{
Thread.sleep(1);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
for (; line < 220; line++)
{
increase = (line*100/numOfLinesToRead);
if (increase != 0)
{
increaseProgressBarOnActivity(increase);
try
{
Thread.sleep(90);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
Despite you having already tried AsyncTask, I still would strongly recommend to use it.
Just take a look at the onProgressUpdate() method. It is made to update the UI from AsyncTask.
Here is an example of how it could look like:
private class DownloadFilesTask extends AsyncTask<String, Integer, Long> {
private ProgressDialog progressBar;
#Override
protected void onPreExecute(){
super.onPreExecute();
progressBar= new ProgressDialog(getApplicationContext());
progressBar.setMessage("Loading...");
progressBar.show();
}
protected Long doInBackground(String... params) {
long someLong;
// do something here with params
// the Integer variable is used for progress
publishProgress(i);
// call it for example while downloading a file
return someLong;
}
// this is called whenever you call puhlishProgress(Integer)
protected void onProgressUpdate(Integer... progress) {
progressBar.incrementProgressBy(progress[0]);
}
// the onPostexecute method receives the return type of doInBackGround()
protected void onPostExecute(Long result) {
// do something with the result
progressBar.dismiss();
}
}
You said your problem was getting the Context. Well: Service is a Context
So you could simply make the AsyncTask an inner class of your Service and then use its Context.
in my app in android, i need change background image in image view on 10 seconds once. so that i call a Async Task within a run method. when I execute the app it crashes.
It gives the Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() Exception to me.
I know I have to use Thread, but I do not know how to do so properly. Please help me.
This is my code sample:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
.................
new Thread()
{
public void run()
{
while(true){
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
count = count + 1;
new ImageChange().execute();
}
}
}.start();
} // OnCreate End
class ImageChange extends AsyncTask<Void, Void, Void>
{
protected void onPreExecute() {
}
protected void onPostExecute(Void unused) {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
protected Void doInBackground(Void... arg0) {
switch(count){
case 1:
b1 = BitmapFactory.decodeFile(f1.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f2.getAbsolutePath());
break;
case 2:
b1 = BitmapFactory.decodeFile(f2.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f1.getAbsolutePath());
break;
default :
count = 0;
b1 = BitmapFactory.decodeFile(f1.getAbsolutePath());
b2 = BitmapFactory.decodeFile(f2.getAbsolutePath());
break;
}
return null;
}
}
You're calling the AsyncTask from a worker Thread. This way it has no access to the UI thread. You probably should consider using a Handler.
Probably, the problem is that you must execute the ImageChange.doInBackground() method in the UI thread. Try to change your code like this:
class ImageChange extends AsyncTask<Void, Void, Void> {
Activity act;
public ImageChange(Activity act) {
this.act = act;
}
protected void onPostExecute(Void unused) {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
protected Void doInBackground(Void... arg0) {
switch(count) {
case 1:
helperMethod(f1.getAbsolutePath(), f2.getAbsolutePath());
break;
case 2:
helperMethod(f2.getAbsolutePath(), f1.getAbsolutePath());
break;
default :
count = 0;
helperMethod(f1.getAbsolutePath(), f2.getAbsolutePath());
break;
}
return null;
}
private void helperMethod(String a, String b) {
act.runOnUIThread(new Runable() {
public void run() {
b1 = BitmapFactory.decodeFile(a);
b2 = BitmapFactory.decodeFile(b);
}
});
}
}
Note that you must pass an Activity to the ImageChange class constructor. It means that you have to call the asyncTask in this way:
new ImageChange(this).execute();
Also consider the possibility of using the class TimerTask
EDIT: Change the Activity part of your code with this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
.................
new ImageChange().execute();
} // OnCreate End
And add the while(true) to the ImageChange class:
protected Void doInBackground(Void... arg0) {
while(true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = count + 1;
switch(count) {
...
}
}
return null;
}
EDIT2: You can solve the problem about onPostExecute inserting the code that must be execute after each iteration inside the while loop:
protected Void doInBackground(Void... arg0) {
while(true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = count + 1;
switch(count) {
...
}
act.runOnUIThread(new Runnable() {
public void run() {
iv1.setImageBitmap(b1);
iv2.setImageBitmap(b2);
}
});
}
return null;
}
The code you insert inside the while loop must run in the UI thread; in fact, every onPostExecute method of the AsyncTask class runs on UI thread.
i solved the problem by using Handler Thread.
Ok this is a very weird problem I am having, and I'm pretty sure that I am messing up somewhere, but I can't quite figure out where.
What I am trying is -
Schedule a Timer to execute a TimerTask every five seconds
The TimerTask in turn executes an AsyncTask (which in this case simple sleeps for a second before returning the static count of the number of AsyncTasks).
Finally, the aforementioned count is updated in the UI.
And of course, the appropriate Handlers and Runnables have been used to post asynchronous messages from other threads to the UI.
This code executes only once. I expect it to fire every 5 seconds. Here's the code.
Note: I had no idea what to do with the Looper. I put it there after trial and error!
public class TimerAsyncMixActivity extends Activity {
public static final String TAG = "TimerAsyncMix";
static int executionCount = 0;
Handler mHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Timer().schedule(new MyTimerTask(this), 0, 5000);
}
class MyAsyncTask extends AsyncTask<String, Void, Integer>{
#Override
protected Integer doInBackground(String... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ++executionCount;
}
#Override
protected void onPostExecute(Integer result) {
mHandler.post(new UpdateUiThread(TimerAsyncMixActivity.this, result));
super.onPostExecute(result);
}
}
}
class MyTimerTask extends TimerTask{
private TimerAsyncMixActivity tma;
public MyTimerTask(TimerAsyncMixActivity tma) {
this.tma = tma;
}
#Override
public void run() {
Looper.prepare();
Log.d(TimerAsyncMixActivity.TAG, "Timer task fired");
tma.new MyAsyncTask().execute();
Looper.loop();
Looper.myLooper().quit();
}
}
class UpdateUiThread implements Runnable{
int displayCount;
TimerAsyncMixActivity tma;
public UpdateUiThread(TimerAsyncMixActivity tma, int i) {
this.displayCount = i;
this.tma = tma;
}
#Override
public void run() {
TextView tv = (TextView) tma.findViewById(R.id.tvDisplay);
tv.setText("Execution count is : "+displayCount);
}
Can anyone point me to what I'm doing wrong?
techie, this is how I implemented similar things. I'm won't claim that this is the best way, but it has worked for me and doesn't look too bad.
I have the following code in my activity. I create an async task when the activity starts and I stop it onPause. The AsyncTask does whatever it needs to do, and updates the UI on onProgressUpdate() (which is run on the UI thread, so there's no need to use a Handler).
private Task task;
#Override
protected void onPause() {
task.stop();
task = null;
}
#Override
protected void onResume() {
task = new Task();
task.execute();
}
private class Task extends AsyncTask<Void, String, Void> {
private boolean running = true;
#Override
protected Void doInBackground(Void... params) {
while( running ) {
//fetch data from server;
this.publishProgress("updated json");
Thread.sleep(5000); // removed try/catch for readability
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if( ! running ) {
return;
}
String json = values[0];
//update views directly, as this is run on the UI thread.
//textView.setText(json);
}
public void stop() {
running = false;
}
}
Do not use a timer. If your phone goes to sleep, the timer is suspended too. Use AlarmManager.