Android AsynchTask in Linear Layout - Method must be called from UI Thread - android

I'm using AsynchTask in my app to save a record to a server.
The method that I use in my doInBackground doesn't do anything at all with the UI but I'm getting the following error
Method tryThis must be called from the UI thread, currently inferred thread is worker
Like I said nothing was happening that involved the UI. So I've stripped back my code to try to identify the problem and it is now pretty much bare.. see below
You will notice that rather than the AsynchTask code being in an extension of Activity it is in an extension of LinearLayout as I am using this is for a custom view. I strongly suspect that this is where the root of the problem lies but I don't understand why and nor do I know how to get around it.
public class ExerciseView extends LinearLayout {
public ExerciseView(Context context, AttributeSet attrs) {
super(context, attrs);
}
private class saveRecordTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
String returnString = "";
try {
returnString = tryThis();
//
} catch (Exception e) {
e.printStackTrace();
}
return returnString;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
//startProgress();
}
#Override
protected void onProgressUpdate(String... text) {
// Things to be done while execution of long running operation is in
// progress. For example updating ProgessDialog
}
}
public String tryThis() {
String hi = "hi";
return hi;
}
}
I guess I could use an interface in the custom view to give the data to the Activity at the right time and then do the AsynchTask in the Activity but I'd really like to keep everything together in the custom view to minimise the amount of code that needs to written each time I use it.

Try this. It would help.
If you want to call tryThis() inside UI thread call it as following
runOnUiThread(new Runnable() {
#Override
public void run() {
tryThis();
}
});

Related

How to work with AsyncTask and threads?

The goal:
Using Google App Engine server and Android client, I'm trying to put on the Google map at the Android client Users overlays. Every 30 seconds I'm polling the server and getting Vector that contains users and adding it to the map.
Current status:
I'm dong all that using in one new thread, So after running the app I got:
weird behaviors(delayed overlays, multiple overlays) and after that crushed with ConcurrentModificationException.
After reading a bit i figured out that I need to work with AsyncTask.
Correct me if I'm wrong,But I understand that everything done in the Activity at at onCreate is "running" in UIhread so I need to put the "Logic" (All the Network handling) in doInBackground and all the UI Handling like putting overlays on the map in onPostExecute.
My Question are:
1) In the current status I'm doing:
new Thread()
{
#Override
public void run()
{
super.run();
while(true)
{
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
putNewOnlineUserOnTheMap();
}
}
}.start();
What is the right way to convert this To AsyncTask?
Do I poll the server still using new thread in the doInBackground or there is right way to do this?
2) Is there a specific list of what counts as UI to put in onPostExecute or any concepts list?
In my case I guess that in need to put putNewOnlineUserOnTheMap() in onPostExecute.
Thanks.
Something similar to the following:
class UpdateTask extends AsyncTask<Void, Vector, Void>{
#Override
protected Void doInBackground(Void... params) {
// this is running in a background thread.
while (!isCancelled()) {
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
// send the result back to the UI thread
// onProgressUpdate will be called then
publishProgress(responseFromServer);
}
return null;
}
#Override
protected void onProgressUpdate(Vector... values) {
// this is executed on the UI thread where we can safely touch UI stuff
putNewOnlineUserOnTheMap(values[0]);
}
}
You can't use the result of the task since the task is finished then. But you can use the progress publishing mechanism to get periodic results. If you use it like that and do the modification on the UI thread you should not get ConcurrentModificationException because you do the modifications on the one thread that can safely modify the UI.
One thing to note here: create new instances of your Vector in the background thread and then use it to update the UI. But don't touch the same object afterwards in the backgroundthread. That way you don't need any synchronization since after the background thread sends it away it is only the UI thread that touches it. (and you could use a simple ArrayList instead of a Vector)
AsyncTask uses generics and varargs.The parameters that are passed to the asyntask are . TypeOfVariableArgumentsParameters is passed into the doInBackground(), ProgressParam is used for progress information and ResultParam must be returned from doInBackground() and is passed to onPostExecute() as parameter.
example:--
protected class ParsingTask extends AsyncTask> {
private ProgressDialog loadingDialog = new ProgressDialog(JsonParserActivity.this);
protected void onPreExecute() {
loadingDialog.setMessage("loading app store..");
loadingDialog.show();
}
#Override
protected ArrayList<Items> doInBackground( Context... params ) {
// do ur process here.
return result;
}
if (!this.isCancelled()) {
}
return result;
}
#Override
protected void onProgressUpdate(String... s) {
super.onProgressUpdate(s);
Toast.makeText(getApplicationContext(), s[0], Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute( ArrayList<Items> response ) {
//if u r dealing with list view and adapters set the adapter here at the onPostExecute()
loadingDialog.dismiss();
}
#Override
protected void onCancelled() {
super.onCancelled();
Toast.makeText(getApplicationContext(), "The operation was cancelled", 1).show();
}
}
You can use AsyncTask like below. Hope this will help you..
Class YourClass{
void YourClass(){
NetworkTask nT = new NetworkTasK();
nT.execute();
}
}
protected class NetworkTask extends AsyncTask<Void, String, Boolean>
{
#Override
protected Boolean doInBackground(Void... params)
{
try
{
String response;
while(keepreceiving)
{
response = in.readLine();//Prog Counter stops here until getting i/p.
if(response != null)
yourFunctionForResponse(response);
}
}
catch (Exception ex)
{
}
return null;
}
private void yourFunctionForResponse(String response){
//things to do....
}
}
You may also try runOnUiThread(Runnable action) along with this to implement your work.

doInBackground calling AsyncTask then sleeps blocks UI Thread

I have an activity, composed of an AsyncTask aiming to launch a request when the user clicks on the button. I have been looking for answers, but I didn't find the same problem, or it didn't the same for me. The code is doing what I want, but the ProgressDialog looks blocked as the spinner is not turning sometimes (almost all the time).
When I click on the button :
AsyncTask is launched -> showDialog() is called onPreExecute -> startSearch ( SearchManager launches a new AsyncTask with in the doInBackground there is a heavy call with network ) -> doInBackground in Activity waits for SearchManager to be loaded -> display.
Code for button :
button_search.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new SearchTask().execute();
}
});
Code for AsyncTask in Search Activity :
private class SearchTask extends AsyncTask<Void,Void,Void>{
#Override
protected void onPreExecute(){
showDialog(DIALOG_LOADING_ID);
searchManager.startSearch();
}
#Override
protected Void doInBackground(Void... params) {
while(searchManager.isLoading()){
try {Thread.sleep(150);} catch(Exception e){};
}
return null;
}
#Override
protected void onPostExecute(Void ret){
try {dismissDialog(DIALOG_LOADING_ID);} catch (Exception e){};
if ( searchManager.errorOccurred() ){
//Error
} else {
//No Error
}
}
Code for SearchManagerAsyncTask : which is directly launched by startSearch
protected class SearchAsync extends AsyncTask <Void,Void,Void>{
#Override
protected Void doInBackground(ComSearchAds... datas) {
global.getDataManager().doSearch();
//... When finished
setIs_loading(false);
}
}
I'm apparently doing something wrong, but can't find what and how to avoid this. Thanks for your help !
SOLUTION :
Finally, it appears that the not spinning ProgressDialog was because I was using the same instance of ProgressDialog and
showDialog(DIALOG_LOADING_ID);
//doInBackground
dismissDialog(DIALOG_LOADING_ID);
used with causes problem, I changed to
removeDialog(DIALOG_LOADING_ID)
and now it's working fine.
Thanks All, and hope it can help someone someday !
You don't need to create another task , just instead of doing the search stuff via another activity.
all you need to do is to put you search cod ein doInbackGround() of search task. e.g
#Override
protected Void doInBackground(Void... params) {
global.getDataManager().doSearch();
return null;
}
also use class level variable to get search result to store true/false
#Override
protected void onPostExecute(Void ret){
// Set you result here
setIs_loading(my_searh_result);
try {dismissDialog(DIALOG_LOADING_ID);} catch (Exception e){};
if ( searchManager.errorOccurred() ){
//Error
} else {
//No Error
}
}
Could you please try to add a ProgressBar control in your layout file and set its Visible to true when starting async task and set to gone when end of process reached. Below is the code for the same.
<ProgressBar
android:layout_width="wrap_content"
android:id="#+id/progressBar1"
android:layout_height="wrap_content"></ProgressBar>
It's hard to say, but try this for onClickListner:
button_search.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new SearchTask().execute();
setIs_loading(true);
searchManager.startSearch();
}
});
It's a pretty wild guess, but it might work

How to run queries in the background

I have listed of products with different category. I have to sort them. Because of the queries, It is taking more time to load. Between two activities, the screen is coming black. I want to run the query in the background. How can I do that and how to use its result in main activity?
private class InsertTask extends AsyncTask {
String cat;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(String... params) {
Boolean success = false;
try {
category(cat);
success = true;
} catch (Exception e) {
if(e.getMessage()!=null)
e.printStackTrace();
}
return success;
}
#Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
}
private void category(String category) {
try{
Cursor1 = mDbHelper.fetchcategory(category);
}catch(Exception e){
Log.v("Excep", ""+e);
}
}
And when called
InsertTask task = new InsertTask();
task.execute();
I have listed the category in buttons. How can I get the values then?
You should use AsyncTask for that. And some more info.
Its good you have thought of AsyncTask. Firstly, you can declare this class as inner in you class activity (if you haven't previously did) and so you are able to access you view class members.
You can do this also by creating thread and one handler that will be used to update your UI components. Remember that if you use threads you'll need to lock/unlock your database object because of the thread safety(if any other thread is accessing the database for any reason). Read more about thread safety of dbs.
I was doing some searching myself, and I came across this read, its rather long but looks extremely helpful, with lots of code examples. (I bookmarked it for myself).
Threads, Async, and Handlers O MY!
But some form of threading is the ticket.
From Android dev.
(My favorite code snippet)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
//Do Work here
}
}).start();
}

how to do dynamic loading in android?

i have an rss feed that comes via an XML. There are several events that are returned with information about them. The events are returned with tags...for eg: ....info...
as soon as i encounter tag, i want to update the listview that i am using to show the events.
So the user does not see the loading progress dialog, rather he sees the events getting added to a list.
How do i do this.
thank you in advance.
Here's pseudo codeish example for one way of doing this using SAX parser;
// MyParserThread is assumed to be inner class of Activity here.
private class MyParserThread extends Thread implements MyParserObserver {
private MyParser mParser;
public MyParserThread() {
mParser = new MyParser();
mParser.setObserver(this);
}
public void run() {
try {
// load xml
mParser.parse(xml);
} catch (Exception ex) {
}
}
public void onMyParserEvent(final DataReceivedFromParsing data) {
runOnUiThread(new Runnable() {
public void run() {
// update data to your UI.
}
});
}
public void cancel() {
mParser.cancel();
}
}
And in your parser you're implementing ContentHandler
public void cancel() {
mCancelled = true;
}
public void startElement(....) {
if (mCancelled) {
// If you want to stop Thread from running, all you have to do
// is make parsing stop.
throw new SAXException("Cancelled");
}
....
}
And triggering parsing once your onCreate is called would be;
public void onCreate(...) {
...
mParserThread = new MyParserThread();
mParserThread.start();
...
}
Now this isn't perfect but hopefully gives some idea how to do Thread handling for this purpose. Fundamentally you just have start it, and adding 'cancel' functionality is somewhat more of a bonus - e.g. for cases in which Activity is destroyed while your Thread is running.

Android: display image during async background streaming task

I am trying to retrieve JPGs from an MJPG Stream using an async task. I first thought, i could let the task continuously be running and just letting the buffered JPGs pop up in the onProgressUpdate() method. But this doesn't seem to work, because the method only displays integers, no drawables...what I tried:
private class StreamTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
image = readMJPGStream();
return null;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
imView.setImageDrawable(image); // << doesn't work
}
}
Do you have any ideas? What approach should I try?
Thank you very much in advance!
Huck
When you start a AsyncTask, the doInBackground is called, but it is only run once. I'm not sure what readMJPGStream does, but assuming it blocks until an image is retrieved, its certainly possible that onProgressUpdate gets called several times while your image is still null, then once image get set to something valid and doInbackground quickly exits, there are no further calls to OnProgressUpdate.
You should probably put the call to imView.setImageDrawable in onPostExecute to make sure it gets called when the image has been downloaded. You may also need to call invalidate() on your image view to ensure it gets redrawn. Additionally, if you intend to loop and continue downloading images, you'll need to devise a mechanism of triggering updates. In reality, the issue you're having is because you want 'on demand' get on the UI Thread, but you're dependent on calls to onProgressUpdate. You'd have much better luck using a Handler and your own Runnable/Thread because then when an image download completes, you can post to the UI thread (using the Handler) without having to wait for the onProgressUpdate.
I now got it running this way:
public class StreamActivity extends Activity implements Runnable{
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imView = (ImageView) findViewById(R.id.imView);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void run() {
while (connected){
image = readMJPGStream();
handler.sendEmptyMessage(0);
}
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
imView.setImageDrawable(image);
}
};
public Drawable readMJPGStream() {
//...
return image;
}
}
The only problem is that my while loop is not fast enough. Any ideas are very much appreciated!
Huck

Categories

Resources