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?
Related
I am not writing my whole code, I have the following simple structure:
public class CreateEventActivity extends ActionBarActivity{
int x;
void onCreate(){
new AsyncTask1().execute();//here I change the value of x
Log.i("000000",String.valueOf(x));
}
public AsyncTask1 extends AsyncTask<Void, Void ,Void>{
// process include changing the vlaue of x to 4
Log.i("111111",String.valueOf(x));
}
}
in the log: the log with the tag 000000 appears before the log with tag 111111 what's going on?
First I thought the problem was because I am chainging the value of x in onPostExecute so I did so in doInBackground and the problem still the same.
what's going on?
AsyncTask is asynchronous. Quoting the documentation:
This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
The reason that you use an AsyncTask is to do work in a background thread (e.g., download some data), followed by some work on the main application thread (e.g., update the UI based upon that data).
is there anyway to avoid this?
Get rid of the AsyncTask, or learn how to use it properly. Among other things:
Do not modify the same data in multiple threads without appropriate synchronization logic
Do not try to fork a background thread, then block the main application thread (which appears to be what you want), as that eliminates the entire point of the background thread in the first place
If you have work that you want to do when doInBackground() ends, put that work in onPostExecute(), not in statements that follow your execute() or executeOnExecutor() call.
That's the nature of an Async task.
Async Tasks are mostly being used for long running operations; like webcalls, I/O operations and so on as they can take a while.
If you want to have a callback when the AsyncTask finishes you can override the OnPostExecute() method
first of all I'm sorry about my English level, I'm Spanish.
I have a little problem with a progressBar in SWT application:
I have 1 Class(The application (SWT)) with all controls(progressBar, textboxes, combos, etc).
I have 1 Thread class who makes a file upload to an FTP server.
My problem is, I'm getting invalid thread access when I try to update my ProgressBar.Selection(int) from my UploadThread.
I'm trying hard to solve this problem, with Timertask(I wanna upload my progressBar every second), with events (an Event fires when UploadThread stay active) but it didn't work.
I hope you can help me with this problem.
When you use SWT, you must remember that all access to SWT objects must be performed in the SWT UI Event thread. There are a few exceptions to this, but they are typically noted in the API or rather obvious.
To make any changes to a control use the following template:
c.getDisplay().asyncExec(new Runnable() {
#Override
public void run() {
if (c.isDisposed()) return;
// ...
}
});
This will run the Runnable object in the event thread at the soonest possible time. You can even use this construct in the event thread itself, to postpone work for later - usually to get a rapid UI response.
The if (c.isDisposed()) return; construct is here to guard against the situation where the control is disposed in the time between asyncExec(...) and run() are executed.
If you need to wait for the result to be performed, use syncExec(...) instead of asyncExec(...).
How are you creating your upload thread?
If your thread implements IRunnableWithProgress and is run by a class that implements IRunnableContext, your progress bar should be able to run in a separate thread fine.
Just specify true for the fork parameter on the run method.
The run method on IRunnableWithProgress provides an IProgressMonitor for your thread to update.
Is there any way on Android to know, if the thread running my code, is the UI Thread or not ? In swing there was SwingUtilities.isEventDispatchThread() to tell me if i am on the UI Thread, or not. Is there any function in the Android SDK that lets me know this ?
Answer borrowed from here: How to check if current thread is not main thread
Looper.myLooper() == Looper.getMainLooper()
Any Android app has only one UI thread, so you could somewhere in the Activity callback like onCreate() check and store its ID and later just compare that thread's ID to the stored one.
mMainThreadId = Thread.currentThread().getId();
Anyway, you can omit checking if you want to do something on the UI thread and have any reference to Activity by using
mActivity.runOnUiThread( new Runnable() {
#Override
public void run() {
...
}
});
which is guaranteed to run on current thread, if it's UI, or queued in UI thread.
Yes, there is a way.
Check the current thread object against main lopper's thread object. Main looper is always in the UI thread.
boolean isOnUiThread = Thread.currentThread() == Looper.getMainLooper().getThread();
Hum actually due to Android architecture, all Activities run in the main thread, ie the UI thread. So when you are coding an activity, everything that is in your Activity is in the UI thread.
That is why in Honeycomb an error have been added when you are making network calls in the main thread : it totally blocks the UI.
So by default you are in fact always working in the UI thread.
Another thing : unless you explicitely ask it to be in another thread, a Service will operate on the same thread as the activities of its application.
So, what to do ?
When you have to do heavy calculation in your activity; one solution is to use an AsyncTask (a class designed to allow you to easily use another thread). The code in onExecute() is run in another thread (but be cautious postExecute runs in your main thread). Another one is to manually start a new thread when AsyncTask is not really adapted.
If you create a service that does costly background tasks, make it run in another thread with the android:process=":my_process" attribute of the manifest. You will need to create an AIDL to communicate with this separated service, but it is not a complicated task.
Many objects, like for example the MediaPlayer, have Async variations of their methods. Try to to always use them.
Put a breakpoint where you want to check and, when it gets hit, check if you can interact with your UI (ie, if the UI is not frozen). If you can't interact with the UI then you are in the UI Thread, otherwise you are in a background thread.
I have a splash page on my app, and what I want to do is initiate a background task to start downloading things so they're ready when the user needs them.
So for example a picture of the week or something.
Splash screen starts (start background task)
Splash screen finishes (background task still working)
Home screen starts (temporary "loading" place holder)
User navigates to another activity
Download finishes
User returns to home screen which is updated with picture of the week
Now I'm aware of Async Tasks, but I've heard that async tasks get canceled on finish() and I've also heard they don't get canceled.
Is this sort of task, background loading best handled in a service?
Can anyone provide me with a tutorial on loading things like this in the background?
EDIT:
People are mentioning that UI work should be in the UI and non-UI in the non-UI. I've considered handlers, but does the listener work when the current activity isn't active?
Lets say I start a handler in the main and then switch pages. When I come back I'm pretty sure the main UI won't be updated because the listener didn't trigger while I was viewing another page.
I'm assuming I'll have to create a class just for storing variables or something. Once the service finishes, it'll set a "pic_of_week_loaded" to true and when the main reloads it checks this var. How would I go about this?
You can extend from Application class, create a thread (or AsyncTask) within it that will basically download stuff from Internet. After it finishes, you can notify the home screen activity to show up the contents into the place holder.
Another choice is to use the Android Asynchronous Http Client
I would just do it in the activity but make sure to check that the activity is still active when you go to display it (make sure onDestroy hasn't been called on it yet)..
Then I would cache the result so you don't have to load it again from the web (store the date in the filename so you know which date the picture is for so you know if the cache holds the latest one already).
Consider using IntentService to do your background job, so you will not be bond to activity life cycle.
EDIT: as per comments.
Using own application object is quite simply. Just create it like this:
final public class MyApplication extends Application {
....
}
then update your Manifest to look like this:
<application
android:name=".MyApplication"
...
and theoretically that's it. You can now add your own methods there, incl. async task operations. And you can get handle to your application object with just MyApplication app = (MyApplication)getApplicationContext(); and then do app.XXX(); Some important notes though: if you'd like to use AsyncTask in your ApplicationObject, be aware of Android Bug #20915. The workaround, as per discussin there is to do this in onCreate():
public void onCreate() {
// Workaround for android bug #20915
// http://code.google.com/p/android/issues/detail?id=20915
try {
Class.forName("android.os.AsyncTask");
} catch (Exception e) {
e.printStackTrace();
}
super.onCreate();
...
I will try to explain why (1) keeping global state in Application sublcass and (2) using AsyncTask are both bad approaches for this case.
(1) OS may kill your app process if the app is not in the foreground and there is no running services in the app at the moment. More details on this in this post: How to declare global variables in Android?
(2) AsyncTask is tricker than it looks at first. :) For instance, if ((OS < 1.6) || (OS >= 3.0)) all tasks are run on the same background worker thread by default. I mean ALL tasks for the current Java process are executed on the only background thread. So the next possibly started tasks in other activities will have to wait untill that first/init one is done. I think this is not what you'd like to get (if user navigates from Home activity to some other activity and that another activity will need to load some data using AsyncTask, then make sure your first/init task is done quickly, because it will block any subsequent tasks). Of course, if the amount of work for the first/init task is not big, then you can don't worry about this point. More details on how AsyncTask works in this post: Running multiple AsyncTasks at the same time -- not possible?
So my advice would be to use IntentService to download the image/date you need on startup. Once it downloads the data it sets the flag in SharedPreferences and sends a broadcast. By this time the Home activity may be in 3 states:
active (passed onResume(), but not yet onPause())
paused (passed onPause(), but not yet returned to onResume)
destroyed
While it is active it uses broadcast receiver to listen to the service. When it is paused it unregisters the broadcast receiver, but when it comes to active the first thing it does is to check the flag from SharedPreferences. If flag is still not set, then registers broadcast receiver.
1. Well AsyncTask was introduced into android to give what its know for Painless Threading, but i don't think thats the case here....
2. Now Its always good to keep the UI work on the UI thread, and Non-UI work on the Non-UI thread, and that became a rule from the arrival of HoneyComb version of Android.
3. Now as you want to download few things at background, which DOES NOT INCLUDE reflecting the output on the UI. Then i think you look into CountDownLatch Class in the java.util.concurrent.
4. Else you can always run a Non-UI thread at background.
I prefer to use Threads and Handlers for background tasks. The thread will execute some operation in the background, then when the task is complete, update the handler to update the UI. Here is some sample code below:
Handler handler = new Handler() { //Declare this as a global variable to the class
#Override
public void handleMessage(Message msg) {
//display each item in a single line
if(msg.obj.equals("update subcat")){
subcategoryAdapter.notifyDataSetChanged();
}else if (msg.obj.equals("update products")){
productsAdapter.notifyDataSetChanged();
}else if (msg.obj.equals("update cat")){
categoryAdapter.notifyDataSetChanged();
}
}
};
Here is your background task:
Thread background = new Thread(new Runnable() {
#Override
public void run() {
getSubCategories(((Categories)searchResults.get(pos)).ID);
handler.sendMessage(handler.obtainMessage(pos, "update subcat"));
}
});
background.start();
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.