Android - Ending activity from within rendering thread - java

Good afternoon.
I am unfamiliar with the activity life cycle in android and have been reading up as best as possible but I cannot figure how to solve the following in a nice manner.
I have an activity with a GLSurfaceView to draw various things on the screen. In the renderering thread for this GLSurfaceView I perform all the rendering as well as the actual update logic (I will seperate this out eventually).
The trouble I am having is from one of the "screens" drawn within the renderer I wish to end the Activity and have it call the various lifecycle methods.
Normally I might do this with System.exit(0); however ending the activity in this way does not seem to call the OnStop(); OnDestroy(); methods.
This might just be me being silly and not seeing an easy way of doing this but is there a way to access the Activity and call activity.finish(); without having to pass the reference to it all the way down?
This is probably less of an android question and more a general java problem? Sorry I am a little rusty at both. Maybe if someone could explain roughly how they handle an issue like this in their app.

You do need to obey thread safety rules and not call activity.finish() directly from your render thread. The best way to handle this is to post a runnable back onto the event queue for the UI Thread. And let that Runnable call activity.finish().
You don't have to pass the activity down to the area where you plan on stopping the activity. Here is what I'd do. Pass the activity to the class you instantiate in onCreate(). Something like:
public void onCreate( ... ) {
MyRenderer renderer = new MyRenderer( glSurface, this );
}
Then inside MyRenderer I'd do something like:
public void someMethodInRenderer() {
if( stop ) {
stop();
}
}
public void stop() {
Handler handler = new Handler();
handler.post( new Runnable() {
public void run() {
activity.finish();
}
} );
}
Notice the Handler used to post back to the UI thread. That makes it safe to call activity.finish(). I couldn't find any specific information in the docs stating it's safe or not safe to call finish() from another thread so to be on the safe side post it back.
Things to keep in mind. If someMethodInRenderer() is deep within the bowels in your program then you don't have to have access directly to the activity instance. You just need a reference so something that eventually calls to the activity to finish. So maybe there is a reference to another part of the system you are passing down to that method where you can add the stop(). So stop() and someMethodInRenderer() could be in the same class, or in different classes. That's a choice you'll have to make. Eventually this is an architecture issue you have to decide.

If the renderer thread is inside the Activity, you can use ActivityClassName.this.finish();

To address an issue I ran into:
If you finish your activity (including from another thread) via activity.finish() it is important that the render thread's onDraw() method is not blocked (happened to me due to my implementation of double buffer rendering).
In that case, only the onPause() method in the activity class got called. The methods onStop() and onDestroy() weren't called even though the app finished with a short delay.
Hope this helps anybody facing the same problem.
Edit: The reason was, that in my activity.onPause() method I called glSurfaceView.onPause() while the render thread's onDraw() was blocked.

Related

Starting an Activity from Runnable()

Hopefully not a dupe, dug around as best I could and came up with nothing. All the suggestions in SO when I typed the title had less than 0 upvotes, so hopefully I'm not following the same path. My question, essentially, is what will happen if I do this on my main thread:
new Thread(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
startActivity(i);
}
});
}
}).start();
Assuming i is an intent, that I didn't screw anything else up, etc. Obviously this is a very trivial case. But I'm wondering if there's anything I need to do to/on the worker thread? Am I going to cause a memory leak or other issue if I do this? Do I need to make a call to something on the worker thread to tell it that I no longer need it? Will it understand on its own that it's no longer needed? Am I just completely misunderstanding something? Thanks!
Well I am not sure if that is going to work. But if you will go this way you might get memory leaks.
You can achieve activity creation posting an event from asynctask https://github.com/greenrobot/EventBus
, and subscribing to that event in your activities/fragments. You can create base class for multiple activities and subscribing inside it. So you will get event anywhere.
A java Thread will become Dead after finishing execution. You will have a short memory leak until the thread finishes it's task (because the thread is bound to the current activity and that activity is not destroyed until you finish your stuff).
Anyway I would suggest you to use AsynkTask if you want to update the ui after some background task.
If you are more advanced the best solution would be to use RxJava or Live Data. In android we don't use Thread too often since we have other wrappers that ease our communication between threads

Android Webview loadUrl does not work when coming from a worker thread

I am developing an app that contains a web view. A certain times during the app it does a call to Webview loadUrl.
Sometimes the call will come directly from an event on the UI thread and other times it comes from an event on a background worker thread. When it originates from the background thread I do a call to runOnUIThead() to ensure the actual call to loadURL happens on the UI thread.
What I am experiencing is that loadUrl() works fine when originating from the UI thread, however it fails to work when it comes from a worker thread (even though the actual call to loadUrl happens via a runnable I pass into runOnUIThread()).
Having set a break point I can see that in both instances loadUrl() is being called on the UI thread. Yet it works in one case but not the other.
I am currently sifting through the Android Webview source code to see if I can track down why sometimes it works and sometimes it doesn’t. If anyone can shed any light on the matter it would be greatly appreciated.
--- UPDATE ---
I have tried a few suggestions from this post here: WebView loadUrl works only once
Mainly doing the following before calling loadUrl:
webView.clearCache(true);
webView.loadUrl("Url");
And:
webView.clearCache(true);
webView.clearView();
webView.reload();
webView.loadUrl("about:blank");
webView.loadUrl("Url");
Unfortunately neither of them work.
In general, its not safe to create view outside of main thread.
In your particular case, this is not allowed, because WebView creates Handler() in its constructor for communication with UI thread. But since Handler's default constructor attaches itself to current thread, and current thread does not have Looper running, you're getting this exception.
You might think that creating a looper thread (that must be alive at least as long as WebView) might help you, but this actually a risky way to go. And I wouldn't recommend it.
You should stick with creating WebViews in main thread. All controls are usually optimized for fast construction, as they are almost always created in UI thread.
or You can call webview like this
runOnUiThread(new Runnable() {
#Override
public void run() {
// your webview method
}
});

After ASyncTask.execute() do x() from Activity

This is one I'm not sure how to go about.
Basically I have an ASyncTask class thats doing its business as usual in the background. I'd like to do something after its finished. Now before you jump ahead and say "just use onPostExecute()", theres a catch. The method I need run is in the activity and not the Task class.
The way I see it, I have 2 options.
A:
CustomTask task = new CustomTask();
task.execute(passedParams);
//when(task.execute is finished)
{
doX();
}
I hope I can do it this way as Its so simple and lets me check when the task is completed without having to constantly poll it for activity and getStatus() on the activity.
I don't think I'll get this lucky but If anyone has a way of doing it, that'd be great
B:
Pass the activity as a paramater to the ASyncTask. This is messy and I'm not happy about using it but asides from that and the object reference, I don't know if it will work
CustomTask task = new CustomTask();
task.execute(passedParams,MyActivity);
Then in the Tasks onPostExecute, I can just have it call the MyActivity.doX();
C:
A third way would be to make the asynctask a private class in the activity itself but i really would like to keep it separate. Resusability and what not –
Any thoughts on this?
To summarize, Need to doX() after task.execute is finished. Any ideas appreciated.
D:
Ok I know I'm on a roll here. I keep thinking up new solutions. A class method or static method that can be called from any where.
public class ProfileSettings extends Activity
{
public static void doX()
{
//Logic...
}
}
From AsyncTask
MyActivity.doX();
Option B should work and is sometimes a good option, but sometimes I use anonymous classes for this. When you call it from your activity:
CustomTask task = new CustomTask() {
#Override
protected void onPostExecute(Long result) {
super.onPostExecute(result);
MyActivity.this.doX();
}
}.execute();
Option A:
Android API has already provided built-in function for this purpose AsyncTask.get():
CustomTask task = new CustomTask();
task.execute(passedParams);
Result result = task.get(); // <- Block UI thread and waiting for AsyncTask finish.
this.doX(result);
As you can see, this is a bad practice as it blocks UI thread and may cause ANR exception, By doing this, you are actually sacrifice the benefit of AsyncTask, and make it running synchronously with UI thread.
Option B and C:
Both are correct way of doing things, by calling doX() method in onPostExecute() method,
AsyncTask, as its name stated, run a background thread asynchronously with UI thread, and once the background thread is finished, onPostExecute method is called on UI thread. There is no way to tell exactly when onPostExecute method is called (i.e. when doInBackground method is finished) at project build time, as it is determined at app run time, the only thing we know is onPostExecute method is guaranteed to be called on UI thread at some point in the future, In another word, when writing code at project build time, we never know exactly when the doInBackground is finished and code execution jump back to UI thread outside onPostExecute method (Unless you implement some waiting mechanism in code like Option A). So the purpose of onPostExecute method is for processing everything after doInBackground method is finish, this is also why the only argument of onPostExecute method is the result returned from doInBackground method.
The difference between Option B and C is whether to implement AsyncTask as inner class or separate class. This has been aksed and discussed many times in StackOverflow. Most people think it is good to separate them for resusability reason or etc. From my point of view, I don't agree with it. Java Programming Language has its reason provide inner class syntax to suit some special coding situations, when talking about code refactoring from a OOP perspective, think more from problem abstraction level, not simply strip inner class out from Activity class at code level. As you can see in your example, by isolating AsyncTask from Activity, you don't gain any real benefit but rather increase the code complexity (need pass activity context reference between classes) to solve problem.
I think you real question is whether or not we should isolate AsyncTask inner class implementation from Activity. For a better OOP code refactoring (reusability, testability and etc.), checkout my answer in this StackOverflow question to see how to isolate business layer from application UI layer properly.
I was able to implement this feature with an interface:
http://howcanisolve.com/38646/android-java-equivalent-of-ios-block-callbacks
public interface ICallbacks {
public void onResponse(JSONObject response);
public void onError(VolleyError error);
}
Then in your routine code just put a new instance of Callbacks:
public static void getPassagesForFirebaseUser(FirebaseUser user,
Context context, ICallbacks events) {
//here code and call ICallbacks methods
if(result){ events.onResponse(response); }
if(error){ events.onError(err); }
}
ultimately you can call the method with :
getPassagesForFirebaseUser(user, context, new ICallbacks(){
#Override
public void onResponse(JSONObject response){
//Success !!!
}
#Override
public void onError(VolleyError response){
//Error !!!
}
});
Option B is generally safer. But even then, you need to be careful. You need to store the instance of your Activity (not just the class) in the ASyncTask. And if the Activity gets destroyed while the task is running (what if the user presses the Back button?), you need to inform the task of this so the task doesn't try to call a method on a dead Activity.
And if the Activity comes back to life (after a screen rotation, for example) then you need to reattach the new Activity to the running task.
These things are fiddly.

Best method for threading in Android?

I have an animation in which triggers an event. This event fires a lot of computing usage and thus stutters the UI.
What I need to do is keep the thread running smoothly. When the event happens it will pass a string down to the thread, perform calculations (including using the audioRecord class) and return a boolean variable.
I have looked around and it seems AsyncTask may be the best solution, but I wanted to see if any of you had any ideas? Considering performance, Is this the best way to go?
Thanks,
Ben
Generally AsyncTask is fine.
But if you dont need to acess the UI thread for your background operation you can simply use a new thread.
new Thread(new Runnable() {
public void run() {
//do stuff
}
}).start();

Blocking Dialog from within JNI code

I'm writing an app that's basically a wrapper around a 250K JNI. The JNI (a game engine) has APIs like handle_penUp(int x, int y). Sometimes it needs to query the user from inside handle_penUp() (via callbacks into Java code), so the dialog I use to implement the query must block.
I understand that the main thread of execution can't block. So I've spawned a second thread that makes all the JNI calls that might result in callbacks that would need to block. Inside that second thread, when I need to put up a blocking dialog, I call startActivityForResult() and then acquire() on a semaphore. When onActivityResult() gets called on the main thread it calls release() on the same semaphore.
This works if my query is implemented as a new Activity, but not if I want to showDialog() within the existing Activity. Log messages tell me my thread needs a Looper. I'm adding one -- and will append info on whether it works -- but it feels as if I'm going down the wrong path here. What I need is a recipe for doing blocking dialogs (useful if only because every other platform has them and so ported code will often work that way.)
It sound very close to a problem I had with setting visible/invisible some view from the touch thread.
the problem is that you can't do some operations on the GUI form another thread (which is your case)
what you need to do is to use a Handle in your main thread
I declared it in the Activity
public static final Handler handlerVisibility = new Handler() {
public void handleMessage(Message msg) {
int visibility = msg.getData().getInt("visibility");
view.setVisibility(visibility);
}
};
I chose the option of public static so that I can access in anywhere (because I never have more that one call at a time and that I felt lazy to pass it along to the sub classes).
then what you want to do is send a message to this handler and since the Handler is in the same thread as the gui it works ^^
Message msg = MainActivity.handlerVisibility.obtainMessage();
Bundle b = new Bundle();
b.putInt("visibility", View.VISIBLE);
msg.setData(b);
MainActivity.handlerVisibility.sendMessage(msg);
That should solve your looper error and allow you to send GUI request from one thread to another
hope it helps
Jason
You definitely don't want two UI threads. There should be only one thread that communicates with the Android SDK as far as the control flow and display go (i.e. anything related to drawing, starting activities, displaying dialogs, etc).
Also, keep in mind that you don't want to actually keep your thread running - everything is based on events, so you want your code to respond to something, do something, and then exit as soon as possible.
When you say "block", what exactly do you mean? What needs to be blocked? If you simply need to stop responding to events, why not have a boolean that is set to true while the dialog is visible, and simply ignore all events while it is true?

Categories