Android equivalent of iOS's dispatch_after - java

Or any other mechanism to delay code execution without hanging the main thread?

Use a Handler's postDelayed(). Documentation

Java example
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
//logic
}
}, 2000);
or
Thread({
try{
Thread.sleep(2000)
} catch (e: Exception) {
//
}
//logic
}).start()

Related

How Runnable and Thread work

I clearly misunderstand how they work. My code:
private final Runnable processAccel = new Runnable() {
#Override
public void run() {
Log.d(TAG, "run: AccelStart");
registerAccel();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.postDelayed(this, interval);
unregisterAccel();
}
};
During this Runnable i was hoping to record sensor events, in the same class. However I get no data.
If I remove the
unregisterAccel();
it records data all the time, both during the runnable and when it is not running, and during when it is sleeping during the runnable, but as soon as I deregister the sensor listener at the end of the runnable, I stop getting results, even when I extend the Thread.sleep out to 10 seconds, which makes no sense to me?
Extra info:
public void registerAccel(){
Log.d(TAG, "registerAccel: on");
sensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
public void unregisterAccel(){
Log.d(TAG, "unregisterAccel: off");
sensorManager.unregisterListener(this, mAccelerometer);
}

AsyncTask doesn't finish after running doInBackground Android

I'm running an AsyncTask on my TakePic class. In doInBackground function I'm using Camera.takePicture function. Now everything is fine at this point; I'm taking the picture and saving the file to /sdcard/%d.jpg that location.
public class TakePic extends AsyncTask<CameraPreview, String, Integer> {
#Override
protected Integer doInBackground(final CameraPreview... params) {
params[0].camera.takePicture(null,null,new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.e("picture_saved", "Picture has been saved succesfully: " + data.length);
camera.release();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e("file_not_found: ","couldn't save the file "+e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.e("IOexception: ","couldn't save the file "+e.getMessage());
}
}
});
Log.e("doinback_compt:" ,"done");
return 0;
}
#Override
protected void onPostExecute(Integer integer) {
}
}
But after I execute this AsyncTask on my main class it doesn't finish. I need to execute another function and I have to wait until this AsyncTask finishes. So after I execute the AsyncTask I'm using a while loop to check the status of the task but the status never changes.
TakePic backCam=new TakePic();
backCam.execute(cameraPreview_front);
while (backCam.getStatus()!= AsyncTask.Status.FINISHED){
*waiting for async task to finish*
}
It stuck at the while loop and my logcat show that doInBackground running normal, and the file is saving to that location.
10-10 18:06:14.497 15975-15975/com.urun.camera_test E/clicked_capture:: ok
10-10 18:06:14.633 15975-16452/com.urun.camera_test E/doinback_compt:: done
So what am I need to do? Thanks in advance.
This is being handled in an odd way. First CameraPreview.camera.takePicture() will run in the background itself, that is why you pass it the Camera.PictureCallback in the constructor. You are simply stacking threads there. Try this in the main thread
[yourCameraPreview].camera.takePicture(null,null,new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
camera.release();
// Read below
}
}
Now we can just wait for the picture callback. Once we get data back, we can call an AsyncTask to store it in the file, and apply our own callback to wait for it's response. We can utilize a static inner class to make this all work.
private static class ImageSaver extends AsyncTask<Byte, Void, Exception>{
public interface ImageSavedListener{
void onImageSaved(Exception e);
}
private ImageSavedListener mCallback;
public ImageSaver(ImageSavedListener callback){
mCallback = callback;
}
#Override
protected void doInBackground(Byte... data){
if(data == null || data.length == 0)
return new Exception("Data returned from camera is invalid");
try {
FileOutputStream outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d("picture_saved", "Picture has been saved succesfully: " + data.length);
} catch (FileNotFoundException e) {
Log.e("file_not_found: ","couldn't save the file "+e.getMessage());
return e;
} catch (IOException e) {
Log.e("IOexception: ","couldn't save the file "+e.getMessage());
return e;
}
return null;
}
#Override
protected void onPostExecute(Exception e){
if(mCallback != null)
mCallback.onImageSaved(e);
}
}
Then call it like this (in the section stated Read below above)
new ImageSaver(new ImageSavedListener(){
#Override
public void onImageSaved(Exception e){
if(e == null){
// do what you want
}
else
e.printStackTrace();
}
}).execute(data);
This will take the picture in the background, wait for the response, save the response to a file in the background, wait for the response, and then do what you want based on the exception returned after saving.
If you need to do some code after AsyncTask execution, I can suggest one solution.
Wrap your *waiting for async task to finish* code in Runnable and send it as a param to Async task ( but this is not the best solution, just fast one )
new AsyncTask<Object, Void, Runnable>() {
#Override
protected Runnable doInBackground(Object... runnables) {
CameraPreview cp = (CameraPreview) runnables[0];
Runnable callback = (Runnable) runnables[1];
/**your main logic*/
return callback;
}
#Override
protected void onPostExecute(Runnable aVoid) {
super.onPostExecute(aVoid);
if (aVoid != null)
aVoid.run();
}
}.execute( cameraPreview , new Runnable() {
#Override
public void run() {
/**code to run();**/
}
});
Possible problem with your current code is :
You are not executing super.onPostExecute(integer);
Try change code to
#Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
}
As pointed out before, does not make sense blocking your main thread waiting do certain event. However, if you still want to get a something from your AsyncTask, I would advise you to use FutureTask
As I can see in your code, the AsyncTask is finishing correctly.
The problem is that you are taking the picture inside the AsyncTask. So while the Camera.PictureCallback is waiting for the picture the task ends immediately after call the "takePicture" method.
What I should do is something like this (this is only an approach):
public class TakePic {
public interface MyTakePicListener{
void onPictureTaken();
void onPictureError();
}
private MyTakePicListener myListener;
public void takePicture(CameraPreview cameraPreview) {
cameraPreview.camera.takePicture(null, null, new Camera.PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, final Camera camera) {
new Thread(new Runnable() {
#Override
public void run() {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.e("picture_saved", "Picture has been saved succesfully: " + data.length);
camera.release();
HERE you should call a listener to continue with your success code
myListener.onPictureTaken();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e("file_not_found: ", "couldn't save the file " + e.getMessage());
HERE you should call a listener to continue with your error code
myListener.onPictureError();
} catch (IOException e) {
e.printStackTrace();
Log.e("IOexception: ", "couldn't save the file " + e.getMessage());
HERE you should call a listener to continue with your error code
myListener.onPictureError();
}
Log.e("doinback_compt:", "done");
}
}).start();
}
});
}
}
Please, let me know if this could help you.

Android java.lang.NullPointerException inside try/catch

I have the code below (app live, and I got a crash reported at the line with mService.consumePurchase):
Thread trd = new Thread(new Runnable()
{
#Override
public void run()
{
try
{
int response = mService.consumePurchase(3, getPackageName(), sku.mToken);
if (response == 0)
{
System.out.println("onActivityResult consume ok");
purchasesOK.add(sku.mSku);
}
else
{
System.out.println("onActivityResult consume failed");
purchasesFail.add(sku.mSku);
runOnUiThread(new Runnable()
{
public void run()
{
alert("Store Problems!", "There were problems consuming the product, please use RESTORE button.");
}
});
}
} catch (RemoteException e) {
purchasesFail.add(sku.mSku);
System.out.println("onActivityResult consume crashed");
runOnUiThread(new Runnable()
{
public void run()
{
alert("Store Problems!", "There were problems consuming the product, please use RESTORE button.");
}
});
}
}
});
trd.start();
here is the crash report:
java.lang.NullPointerException at
com.XXXXX.GGActivity.j_ItemPurchase(GGActivity.java:1309) at
com.XXXXX.GGLib.step(Native Method) at
com.XXXXX.GGView$Renderer.onDrawFrame(GGView.java:436) at
android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1523)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
I thought that try/catch will show the popup error in any case of exception. Any ideas what might caused it ? Or how can I avoid it?
Thanks,
/C.
Add this:
catch(NullPointerException e){
purchasesFail.add(sku.mSku);
System.out.println("onActivityResult consume crashed");
runOnUiThread(new Runnable(){
public void run(){
alert("Store Problems!", "There were problems consuming the product, please use RESTORE button.");
}
});
}
in order to show the popup message

android: Variable in runOnUiThread

Hi i m using Android Studio, and I am using Deprecated function in a runOnUiThread
It forces me to use a a Final Variable inside the runOnUiThread
this is ok for the new function but for the Deprecated function i get an error
Error:(133, 16) error: incompatible types
required: Thread
found: void
anyone can help to fix this.
Thread thread = new Thread() {
public void run() {
try {
String sURL = "http://pollsdb.com/schlogger/223.png";
URL url = null;
url = new URL(sURL);
assert url != null;
Bitmap bmp = null;
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
bmp = Bitmap.createScaledBitmap(bmp, 200, 200, false);
BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), bmp);
final BitmapDrawable fbmpdw = bitmapDrawable;
runOnUiThread(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
ib1.setBackground(fbmpdw);
} else {
ib1.setBackgroundDrawable(fbmpdw); // <---- this the problem
}
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
your problem is not the setBackgroudDrawable method, but Thread.start(), which returns nothing (void), while you are trying to assign its return value to the thread local variable
You can both change Thread thread = new Thread() { ... } and then call thread.start() or simply new Thread() { ... }.start(); without assignment
Do you need to use the thread variable anywhere else? I don't think you need to.
If so, simply change in your first line
Thread thread = new Thread() {
To
new Thread() {
Your .start() will return void, and you cannot do Thread thread=//some thing void as it is expecting some Thread type.

Wait for a thread before continue on Android

I've one thread, but i'd like to wait for it to finish before continue with the next actions. How could i do it?
new Thread(
new Runnable() {
#Override
public void run() {
mensaje = getFilesFromUrl(value);
}
}).start();
here i'd like to put something (but loops) that knows when thread finishes and evaluate the result (mensaje)
btnOk.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
lblEstado.setText(mensaje);
if(mensaje.equals("Importado"))
startActivity(new Intent(ScanUrl.this, MainActivity.class));
Thread t = new Thread(new Runnable() {
#Override
public void run() {
mensaje = getFilesFromUrl(value);
}});
t.start(); // spawn thread
t.join(); // wait for thread to finish

Categories

Resources