Android managing threads without using AsyncTask - java

I have a project I am working on where I need to improve my knowledge on Threads.
Scenario:
I have an Activity which calls a method Which use uses a thread:
Object soapResponse = soaphttp.fetchNextCatalogueRange(0, numberOfItems);
In the soaphttp class I have:
Thread soapThread = new Thread(new Runnable()
{
private Object serverResponse = new Object();
public void run()
{
// Do network stuff here
}
});
soapThread.start();
try
{
// crude synchronisation
soapThread.join();
}
The problem
Using join() blocks the UI thread.
If I dont use join() I get null pointer exceptions (data sync errors)
The Challenge:
In my activity I would like to do stuff on the UI thread while the soaphttp class is fetching data and then sync i.e tell the UI thread that the data is ready.
for example display a progress bar .. which will terminate when the data has finished being fetched.
How can I do this without having to use AsyncTask ?

At the very end of your thread's run() method, use one of the following:
the post() method of View class,
the runOnUiThread() method of Activity class
in order to refresh your UI in the UI thread.
You can use the same methods to somehow alter your UI at the start of the run() method (make same widgets disabled, show some kind of progress indicator...)

Related

Delay a method in UI thread without blocking it [duplicate]

I want to update my UI from a Thread which updates a Progressbar. Unfortunately, when updating the progressbar's drawable from the "runnable" the progressbar disappears!
Changing the progressbars's drawable in onCreate() on the otherside works!
Any Suggestions?
public void onCreate(Bundle savedInstanceState) {
res = getResources();
super.onCreate(savedInstanceState);
setContentView(R.layout.gameone);
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); //**Works**/
handler.postDelayed(runnable, 1);
}
private Runnable runnable = new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
public void run()
{
//* The Complete ProgressBar does not appear**/
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
}
});
}
}
You should do this with the help of AsyncTask (an intelligent backround thread) and ProgressDialog
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called begin, doInBackground, processProgress and end.
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread immediately after the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
Threading rules
There are a few threading rules that must be followed for this class to work properly:
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Example code
What the adapter does in this example is not important, more important to understand that you need to use AsyncTask to display a dialog for the progress.
private class PrepareAdapter1 extends AsyncTask<Void,Void,ContactsListCursorAdapter > {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(viewContacts.this);
dialog.setMessage(getString(R.string.please_wait_while_loading));
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
/* (non-Javadoc)
* #see android.os.AsyncTask#doInBackground(Params[])
*/
#Override
protected ContactsListCursorAdapter doInBackground(Void... params) {
cur1 = objItem.getContacts();
startManagingCursor(cur1);
adapter1 = new ContactsListCursorAdapter (viewContacts.this,
R.layout.contact_for_listitem, cur1, new String[] {}, new int[] {});
return adapter1;
}
protected void onPostExecute(ContactsListCursorAdapter result) {
list.setAdapter(result);
dialog.dismiss();
}
}
The most simplest solution I have seen to supply a short
execution to the UI thread is via the post() method of a view.
This is needed since UI methods are not re-entrant. The
method for this is:
package android.view;
public class View;
public boolean post(Runnable action);
The post() method corresponds to the SwingUtilities.invokeLater().
Unfortunately I didn't find something simple that corresponds to
the SwingUtilities.invokeAndWait(), but one can build the later
based on the former with a monitor and a flag.
So what you save by this is creating a handler. You simply need
to find your view and then post on it. You can find your view via
findViewById() if you tend to work with id-ed resources. The resulting
code is very simple:
/* inside your non-UI thread */
view.post(new Runnable() {
public void run() {
/* the desired UI update */
}
});
}
Note: Compared to SwingUtilities.invokeLater() the method
View.post() does return a boolean, indicating whether the
view has an associated event queue. Since I used the
invokeLater() resp. post() anyway only for fire and forget,
I did not check the result value. Basically you should
call post() only after onAttachedToWindow() has been called
on the view.
Best Regards
If you use Handler (I see you do and hopefully you created its instance on the UI thread), then don't use runOnUiThread() inside of your runnable. runOnUiThread() is used when you do smth from a non-UI thread, however Handler will already execute your runnable on UI thread.
Try to do smth like this:
private Handler mHandler = new Handler();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameone);
res = getResources();
// pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); **//Works**
mHandler.postDelayed(runnable, 1);
}
private Runnable runnable = new Runnable() {
public void run() {
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
pB.invalidate(); // maybe this will even not needed - try to comment out
}
};
Use the AsyncTask class (instead of Runnable). It has a method called onProgressUpdate which can affect the UI (it's invoked in the UI thread).
You need to create a Handler in the UI thread and then use it to post or send a message from your other thread to update the UI
If you don't like the AsyncTask you could use the observer pattern. In that example use the ResponseHandler as an inner class in your activity then have a string message that will set the progress bars percentage... You would need to make sure that any alterations to the UI are performed within the ResponseHandler to avoid freezing up the UI, then your worker thread (EventSource in the example) can perform the tasks required.
I would use the AsyncTask tho, however the observer pattern can be good for customization reasons, plus its easier to understand. Also im not sure if this way is widely accepted or will 100% work. Im downloading and the android plugin now to test it
As recommended by official documentation, you can use AsyncTask to handle work items shorter than 5ms in duration. If your task take more time, lookout for other alternatives.
HandlerThread is one alternative to Thread or AsyncTask. If you need to update UI from HandlerThread, post a message on UI Thread Looper and UI Thread Handler can handle UI updates.
Example code:
Android: Toast in a thread

How to access main thread from worker thread in Java?

Read many overkilled, overcomplicated solution here in SO, for such an easy question, how to access main thread from a worker thread, to execute some code on it.
In iOS dispatch_get_main_queue() method returns main thread. How in Java?
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0UL), ^{
//do background thread stuff
dispatch_async(dispatch_get_main_queue(), ^{
//update UI
});
});
In Android you can't access the main thread (UI Thread) directly, but you can queue jobs on it, so you need to create a Handler and using that handler to post jobs (Runnable) on main thread.
Below is an example of how you can post on UI Thread using Handler
new android.os.Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//Doing job here
}
})
and also as #CommonsWare mentioned in the comments, there is another ways to access UI thread:
if you have instance of any View you can use View.post(Runnable)
if you have instance of Activity, you can use Activity.runOnUiThread(Runnable)
Btw accessing main thread in Android is totally different than Java Desktop Apps
Running your code on main thread from another:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your code here
}
});
Hope this helps

How to run thread after completing some specific worker thread

I created two swing worker thread class in my swing application. They are load thread, save thread
Load thread is used to load the data from rest service
Save thread is used to push the data to rest service.
My question is that,
How to execute my threads one by one when i create more instance for
load thread?
Save thread should be run after completing process of existing load
thread
Does any one guide me to get solution for this scenario?
Note: I am using Swing Worker class to call rest services.
You should start your save thread in the done method of your load thread.
You can pass your saveThread to the loadThread as constructor argument or define it as class member.
This should work for you;
SaveThread mySaveThread = new SaveThread();
LoadThread myLoadThread = new LoadThread();
class LoadThread extends SwingWorker<String, Object> {
#Override
public String doInBackground() {
//do your work
return "";
}
#Override
protected void done() {
try {
mySaveThread.execute();
} catch (Exception ignore) {
}
}
}
myLoadThread .execute();
If you want to load data from multiple threads, and save this data from one thread after ALL data will be loaded. You can try to use barriers. For example CountDownLatch can wait while all load threads finished their works.

Besides AsyncTask, is there anyway in Android to do something on the UI thread from another thread?

Because for some strange reasons, when I use AsyncTask to connect to a webpage, the UI of my app lags to almost the point of freezing while the AsyncTask is connecting to the webpage.
I thought this was because the connection usually takes quite long, at least 4 seconds.
I want to be able to update my TextView after my Thread have finished, but how do I do that in Android besides using AsyncTask?
There are a few methods to do that:
Use Threads or Runnables
Use Handlers, sending messages to its
Use RunOnUIThread method
Use the method (this is my favorite) post. It's not necessary to use a context/activity instance
For example, you can create a new Handler() and when you want to run code in the main thread do:
public static Handler interfaceHandler = new Handler();
...
mInterfaceHandler.post(new Runnable() {
#Override
public void run() {
//Your stuff
}
});
To complete the information, all Views in Android can make this post(Runnable) . This method add a runnable to their task to do, for that reason is recommendable not use views because the App will slow down. The static handler is perfect to make this work and is very easy to implement
Something like this should work
runOnUiThread(new Runnable() {
public void run() {
// do some stuff here
}
});

Can't create handler inside thread that has not called Looper.prepare() - Android Marmalade

I'm trying to add USB controller support to my Android game. I'm using Marmalade and I've created an extension based on the USB example code. Here it is:
public class GameControllerInput extends Activity
implements InputManager.InputDeviceListener
{
private static final String TAG = "GameControllerInput";
private InputManager mInputManager;
private SparseArray<InputDeviceState> mInputDeviceStates;
private static int numEvents = 0;
public int EDK_GameControllerInput_Init()
{
LoaderActivity.m_Activity.runOnUiThread(new Runnable()
{
public void run()
{
Log.i(TAG, "Running 1 =========================");
}
});
Log.i(TAG, "Init 2 =========================");
return 1;
When I call the init function I get this error:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I've read other threads with this error and they say the solution is to add the LoaderActivity.m_Activity.runOnUiThread(new Runnable() code. However, as you can see, adding this just gives me the same error.
I'm not experienced with Java and I'm at a loss on how to fix this. Any help would be greatly appreciated.
Cheers,
Steve
A Looper (a message queue processor) is tied to a single thread, each thread has at most one looper. A Handler needs to register itself with a Looper to work, so each time you invoke new Handler(), it tries to get the Looper for the current thread (the thread that's creating the Handler), which can be either present or not. The exception that you see is thrown because the thread that's creating the handler does not have a looper.
There is one two things that you can do to fix this:
Add a Looper to the current thread.
Make sure you're creating the Handler on a thread that already has a Looper.
In almost all cases, the handler is used to communicate from a background thread to the UI thread, I'm assuming that's the case here. That means option 2. Your runOnUiThread(Runnable) thing is close, but no cigar, because all it does is write to the log file.
You need to move the code that creates the new Handler() (not shown in your posted code sample) into the runOnUiThread block, or use some other way to get it to run on the UI thread. The typical way to do this is to create it in the onCreate(Bundle) method of your activity or fragment.
Keep in mind that, depending on your initialization order, this may mean it's initially null as seen by your background thread, so the background code will have to be able to deal with that.
Well it's better to have a callback method and mark it as main thread only by calling run_on_os_thread after the method declaration in s4e file.

Categories

Resources