I need to be able to cancel tasks involving web requests.
but I got some issues of memory management and exception handling when something fail.
For example:
I want to create a text edit for searching apps in user device.
so whenever user end a key, I want to clear current search task, and restart search.
The problem I got is in android 4.4, when trying to load the label of the app (to get it's name) I get an exception.
Also of I try to search contacts I'm getting an invlalid uri, fo rcontact photo.
I don't want any help dealing with this errors, I want a solution that will help me ignore this erros (try catach dont work) currently the entire ui get's stuck and app crash.
I'm using the executors service and call cancel when user gives me an input. but it's not enough.
Any advice will be appreciated, thanks.
if you're using AsyncTask i would like to suggest you to make it like this
AsyncTask<Void, Void, Void> a = new AsyncTask<Void, Void, Void>(){
#Override
protected Void doInBackground(Void... params) {
return null;
}
};
a.execute();
// at some point you want to cancel just use
a.cancel(true);
You can even put tasks together in List or array and loop to cancel it whenever you want.
You can try like this: what you want is getting result in background by network and show result in view ,you can Register a Listener to one task,. you can callback method of listener to use show result in view if it get the results in background ,if you do not need the result of current task and want satrt the next task ,you can only remove listener of current task,so the view will not reload
This is my idea ,I am so sorry for my bad english , if you do not see ,you can send message to me, and my email is bjltxsp#gmail.com
Related
How can i take user input from popup dialogue and pass it into a BackGround Async Task?
I have a "createGarden" button. When i click it i want to retrieve a string from user, and pass it to my Background AsyncTask.
In my onClick, i have tried calling String myGardenName = getGardenName(), which returns input from dialogue. Then passing this into my Background task.
new HomeBackgroundTask().execute("create_garden", UserID_String,myGardenName );
I also tried using a value container, and passing this instead of "myGardenName":
String myGN = gnVC.getVal();
HomeBackgroundTask mhomebackgroundtask1 = new HomeBackgroundTask();
mhomebackgroundtask1.execute("create_garden", UserID_String, myGN);
instantiated my 'gardenValueContainer' value container as final in my "getGardenName()" method (enclosing class?) as well as instantiating it in my onCreate()
- I then try SETTING that value from within my onClick (inner class?)
--Also tried calling my HomeBackgroundTask directly from the onClick
Problem
Seems that my create garden always tries to insert a BLANK as the garden name. resulting in "garden "" already exists". When debugging, the user input get's passed through as a paramater, there was an issue with moving from "onPreExectute" to "doInBackground" but now when i'm debugging i get stuck in looper where i can't step over/into/out and my app just says freezes on connecting. (debug halts on a comment line, which might be bad?)
My php scripts work just fine with the same logic for registering a user.
No errors in my console!
http://pastebin.com/2AzWmcM5
Any help greatly appreciated!
"debug halts on a comment line, which might be bad"
Have you tried removing all breakpoints, or putting breakpoints on method implementations rather than on the, say, first line of the method?
I was wondering how I could force a new ASyncTask in Android to be the next task executed. Imagine I have multiple ASyncTask's to load content from the internet, e.g. in my case I pre-load all objects of DataModelA, DataModelB and DataModelC. All the data is loaded to a central application model. I guess my current queue would look like this (but I do not manage it as a queue, yet):
1. DataModelA-Object1
2. DataModelA-Object2
3. DataModelA-Object3
4. DataModelB-Object1
5. DataModelB-Object2
6. DataModelB-Object3
7. DataModelB-Object4
8. DataModelC-Object1
9. DataModelC-Object2
10. ...
I start my tasks like this:
DataModelALoaderTask task = new DataModelALoaderTask();
task.execute("http://my-rest-api.com/datamodel/a");
// and the same for the other tasks
...
The task class looks like this:
private class DataModelALoaderTask extends AsyncTask<String, Void, List<DataModelA>> {
#Override
protected List<DataModelA> doInBackground(String... params) {
String data = params[0];
return DataModelAContentProvider.loadContentFromUrl(data);
}
#Override
protected void onPostExecute(List<DataModelA> models) {
// finally add the loaded content to the central application data model
...
}
}
What I would like to achieve:
Now within my GUI, I like to click on a button and force to load a single part of a model first, because I need to display it right now. Usually this is a task which is already in the queue, but in my case I could also just start a new task, e.g. to load DataModelC-Object2 first before all others are loaded. The queue could load a large number of objects, so that it makes sense to re-schedule a single task or start a new task which does the job immediately.
Any idea how I can handle that? If you would need to see more code snippets, please let me know.
Thanks in advance.
Best regards,
Michael
UPDATE: somehow my question seems to be related to this post. Is that the only way? Or could I simply start a parallel running task using the THREAD_POOL_EXECUTOR? How would I use that?
I have a bit of a problem I cannot solve, since it might a bug or something like that. I would like to make a chart with androidplot, and it works really good, but of course it needs some time to draw it (using hundreds of data), so I use a progress dialog to indicate the loading. But what happens is really weird.
I can define the appearance of the activity when it's loading and when it's loaded. When its loading I define a textview in the background setting its text to "loading" and if it is loaded, that textview contains lots of datas, text etc.
onCreate
{
Thread thread = new Thread(new Runnable() {
public void run() {
-------what needs to be appeared after its loaded ----
Textview -> 12,3245,456,78,789
}
----what is on the screen while the progressbar is on---
TextView -> loading..
}
But most of the time after the progress dialog disappears, nothing happens, the textview still says "loading" and rarely it loads the datas and makes the data appear and changes the textview. What I noticed that the more data I would like to appear the rarelier it stays at the loading phase. Of course everytime the loading progessbar appeers then disappears.
Any Suggestion? It is really weird because I use it in a tablayout and other tabs never do this, always make the data appear.
Thanks in advance!
UP: Okay, its always the first tab, whatever it contains, so the first tab is somehow wrong...
The Andoid UI toolkit is not thread-safe. So, you must not manipulate your UI
from a worker thread—you must do all manipulation to your user interface from
the UI thread. Thus, there are simply two rules to Android's single thread model:
1. Do not block the UI thread
2. Do not access the Android UI toolkit from outside the UI thread
read this for more information on how to access UI elements from outside.
edit::
use AsyncTask ::
onCreate
{
new myLoading().execute();
}
class myLoading extends AsyncTask<Void, Void, Void>
{
protected Void doInBackground(Void ... ) {
.......... do all the loading here .........
}
protected void onPostExecute(Void ) {
Textview -> 12,3245,456,78,789
}
}
I figured out some workaround. I dont have any clue about the solution, my only guess is the loading screen somehow overtake the arrival of all the data and so the chart cannot be drawn. or whatever...
I put a thread.sleep(1000) and now it works.
I have a table with about 1k rows that I want to display. This task obviously chokes the UI thread, resulting in a black screen while the onCreate() builds the table.
I've solved this by using AsyncTask which builds the wanted TableLayout in the "doInBackground" function and display it on the "onPostExecute" function.
Question #1:
Is there any better practice that I'm not familiar with?
Question #2:
My (simplified) "doInBackground" function looks like this:
protected Void doInBackground(Void... v) {
tmpTableLayout = populateTable("");
return null;
}
And my (simplified) "onPostExecute" function looks like this:
protected void onPostExecute(Void v) {
TableLayout ct = (TableLayout)findViewById(R.id.RealTable);
ct.removeAllViews();
/* WHATS HERE? */
}
What should I write instead of the "WHATS HERE?" in the last line of code in order to display the content of "tmpTableLayout" in "ct" ?
Thanks in advance!
Are you sure you want to display it all in one go?
One approach would be to dynamically load in more lines as the user scrolls down. So have a scroll listener that checks if the user is approaching the end of the content that is displayed and therefore start an AsyncTask or a thread loading more content.
Example:
Android List Activity with dynamically loaded images form the web in android
I would probably use a ListView and CursorAdapter and let Android manage fetching the data for you. See the accepted answer here.
I am writing an application that searches a database in "realtime".
i.e. as the user presses letters it updates a search results list.
Since the search can take a while, I need to do the search in background and allow new key presses to re-start a search. So that is a user presses 'a' (and the code starts searching for "a"), then presses 'b' - the code will NOT wait for "a" search to end, then start searching for "ab", but rather STOP the "a" search, and start a new "ab" search.
To do that I decided to do the search in an AsyncTask. Is this a wise decision ?
Now - whenever a keypress is detected, I test to see if I have an AsyncTask running. If I do - I signal it (using a boolean within the AsyncTask) it should stop. Then set a timer to re-test the AsyncTask within 10 mSec, to see if it terminated, and start the new search.
Is this a smart method ? Or is there another approach you would take ?
TIA
First yes, AsyncTask is a good way to do this. The problem I see with your approach is the timer waiting to watch something die. When you invoke the asyncTask hold onto a reference of it. Let it keep state for you so you know if it's out searching or it's has returned. When the user clicks another letter you can tell that asyncTask to cancel. Something like this:
public void onClick() {
if( searchTask != null ) {
searchTask.cancel();
}
searchTask = new SearchTask( MyActivity.this ).execute( textInput.getText() );
}
public class SearchTask extends AsyncTask<String,Integer,List<SearchResult>> {
private boolean canceled = false;
protected onPostExecute( List<SearchResult> results ) {
if( !canceled ) {
activity.handleResults( results );
}
}
public void cancel() {
canceled = true;
}
}
This is safe because onPostExecute() is on the UI thread. And cancel() is only called from the UI thread so there is no thread safety issues, and no need to synchronize. You don't have to watch a thread die. Just let the GC handle cleaning up. Once you drop the reference to the AsyncTask it will just get cleaned up. If your AsyncTask blocks that's ok because it only hangs up the background thread, and when the timeout hits it will resume by calling onPostExecute(). This also keeps your resources to a minimum without using a Timer.
Things to consider about this approach. Sending a new request everytime a new letter is typed can overload your servers because the first few letters are going to produce the largest search results. Either limit the number of results you'll return from the server (say 10-50 results max), or wait until they've entered enough characters to keep results down (say 3). The cons of making the user type more characters is the feedback doesn't kick in until 3 chars. However, the pro is it will dramatically reduce the hits on your server.