I want to start an AsyncTask inside another AsyncTask.
I'm trying to do this by starting the second AsyncTask in 'onPostExecute' of the first AsyncTask. The result is that the second AsyncTask starts after the first has finished.
How can I solve this?
Thank you
here's the code
private class Parse extends AsyncTask<Void, Void, Void>{
Document doc = null;
Element son = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
try {
doc = Jsoup.connect("MY_URL").get();
son= doc.body();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
for(CONDITION){
//MY_CODE
new DownloadImageTask().execute();
}
}
}
This is the second AsyncTask
private class DownloadImageTask extends AsyncTask<String, Void, String> {
Bitmap bitmap;
ImageView image = new ImageView(Events.this);
#Override
protected void onPreExecute() {
};
protected String doInBackground(String... urls) {
try {
URL url = new URL("MY_URL");
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
First, please refer to the oficial documentation to have a best understanding about AsyncTask: http://developer.android.com/reference/android/os/AsyncTask.html
The onPostExecute runs in the main thread, after the background task finishes. This method is designed this way to be used to comunicate with the UI thread to handle the execution.
If you want to run the second AsyncTask with your background code, or just after it started, you have to do this on the doInBackground method.
Related
I am trying to change the wallpaper of Android every 15 minutes or something like this. A user can choose the time and I am running a periodic work using Workmanager.
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(SomeWorker.class, 15, TimeUnit.MINUTES).build();
WorkManager.getInstance().enqueue(periodicWorkRequest);
This way I am calling my Worker Class. The working class is this
public class SomeWorker extends Worker {
Context context = getApplicationContext();
private String URL;
#NonNull
#Override
public Result doWork() {
new FetchWallpaper().execute();
return Result.SUCCESS;
}
private class FetchWallpaper extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... voids) {
try
{
URL = "myurl.com";
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(URL)
.build();
Response responses = null;
try {
responses = client
.newCall(request)
.execute();
String jsonData = responses.body().string();
JSONArray jsonArr = new JSONArray(jsonData);
JSONObject c = jsonArr.getJSONObject(new Random().nextInt(jsonArr.length()));
String imageUrl = c.getString("wallpaper");
Bitmap result= Picasso.with(getApplicationContext())
.load(imageUrl)
.get();
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(result);
} catch (Exception ex) {
ex.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
Date currentTime = Calendar.getInstance().getTime();
}
catch (Exception e)
{
Date currentTime = Calendar.getInstance().getTime();
}
return null;
}
}}
On that Particular line,
new FetchWallpaper().execute();
I am getting the error saying it must call from the main thread. I am new to Android, I don't know if this is the good approach.
Please let me know if there is any better approach to perform such kind of task.
The Worker class already calls doWork on a background thread - you don't need to use AsyncTask at all.
Just move everything from your doInBackground method directly into the Worker's doWork.
You can not update UI from doInBackground method. If you want to do something on UI you must do that on Main UI thread. So write setBitmap code in onPostExecute method as onPostExecute on on Main UI Thread.
To do that set third parameter of AsyncTask as String
AsyncTask<Void, Void, String>
So that return type of doInBackground method will be String
protected String doInBackground(Void... voids)
...
...
return imageUrl;
}
And Your onPostExecute method will be like
#Override
protected void onPostExecute(String imageUrl) {
super.onPostExecute(imageUrl);
Bitmap result= Picasso.with(getApplicationContext())
.load(imageUrl)
.get();
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
new AsyncTask<Void, Bitmap, Bitmap>() {
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap bitmap = null;
try {
InputStream inputStream;
inputStream = new java.net.URL(url).openStream();
bitmap = BitmapFactory.decodeStream(inputStream);
}catch (Exception e) {
logAppE(TAG, "BITMAP ERROR -> " + e.getMessage());
}
return bitmap
}
#Override
protected void onPostExecute(Bitmap s) {
try {
Glide.with(context).asGif().load(s).into(imgViewGIF);
} catch (Exception e) {
logAppE(TAG, "BITMAP -> " + e.getMessage());
}
}
}.execute();
I have an AsyncTask extended class that listens to a port in the background.
My problem is that when I try to add the text that I receive from the socket into a TextView on the UI, the app stops because I'm doing it from outside of the activity thread. What do I need to do to my class to be able to edit the TextView?
Here is the code:
public class Receive_String extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
TextView text_ShowString=(TextView)findViewById(R.id.textView_ShowString);
ServerSocket conn = new ServerSocket(35316);
Socket listen=conn.accept();
BufferedReader input = new BufferedReader(new InputStreamReader(listen.getInputStream()));
String message = input.readLine();
text_Notificari.append(message);
conn.close();
} catch (IOException e) {
e.printStackTrace();}
}
return null;
}
}
Update in onPostExecute(). If you continously reading from port and want to make changes in main UI do it in onProgressUpdate() .
Eg : Make text_ShowString and message global
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
text_ShowString.setText(message);
}
Move your update-the-UI code to onPostExecute() of your AsyncTask.
I want to parse JSON every few seconds. My idea is by constantly parsing it to see if there are some changes in it and if there are to get them and update my views (mostly TextViews). I have a Fragment, called MyFragment. In its onCreateView I am executing the following: new MyTask().execute(myJSONUrl);. Some code:
class MyTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
//getJSONString(String url) - my method for getting the JSON from URL
return getJSONString(params[0]);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (result == null || result.length() == 0) {
Log.w(TAG," JSON IS **null** ");
Toast.makeText(getActivity().getApplicationContext(), "JSON IS NULL", Toast.LENGTH_SHORT).show();
} else {
try{
JSONObject root = new JSONObject(result);
// Here i get what i need from the JSONObject and everything works fine.
} catch (Exception e) {
e.printStackTrace();
}
}
Now how to parse the JSON from URL every n seconds? I have tried using ScheduledExecutorService, Timer and Thread but nothing seems to work. Thanks in advance :-)
When you really throw the battery concerns out of the window:
Change class MyTask extends AsyncTask<String, Void, String> to class MyTask extends AsyncTask<String, String, Void>
Do the following:
protected String doInBackground(String... params) {
//getJSONString(String url) - my method for getting the JSON from URL
while(isCancelled() == false) {
try {
Thread.sleep(1000* 5); // only do this every 5 seconds.
} catch (InterruptException ex) {}
publishResult(getJSONString(params[0]));
}
}
public void onResultPublished(String result) {
// stuff that happened in onResult before...
}
You emit strings as a result and handle it in onResultPublished (this method is executed on the UI thread so it's safe to modify ui here).
Don't forget to cancel the asynctask.
I am trying to display images in a gridView. The images come from an research on an ElasticSearch server. The user give a keyword in a textfield, the result of the query on ElasticSearch is list of string (urls of images) and the images are displayed in the gridView.
The action when I press a button in order to make the research :
public void sendMessage(View view){
imgAdapter.clearmThumbIds(); //mThumbs is a list of string (urls image)
gridView = (GridView) findViewById(R.id.grid_view);
EditText editText = (EditText) findViewById(R.id.searchBar);
String message = editText.getText().toString();
try {
eSearchElastic.ESE(imgAdapter,message);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Etape 2");
gridView.setAdapter(imgAdapter);
}
eSearchElastic.java
public static void ESE (final ImageAdapter imgAdapter,final String keyword)throws ClientProtocolException, IOException {
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>(){
#Override
protected Void doInBackground(Void... params) {
//Build the query, connect to ElasticServer and receive a list or urls of image as answer
System.out.println("Etape 1");
return null;
}
};
task.execute();}
And the result of this print Etape2 before Etape1 and I would like this line "gridView.setAdapter(imgAdapter)" is executed only after the background process/thread of eSearchElastic is finished.
How can I do that?
Just call gridView.setAdapter(imgAdapter); in the onPostExecute() method inside your AsyncTask instead of calling it from sendMessage(). That is guaranteed to be called only after the doInBackground() method finishes, and will be called on the main thread, so it's safe to touch the UI.
eg:
public static void ESE (final GridView gridView, final ImageAdapter imgAdapter, final String keyword) throws ClientProtocolException, IOException {
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>(){
#Override
protected Void doInBackground(Void... params) {
// Build the query, connect to ElasticServer and receive a list or urls of image as answer
System.out.println("Etape 1");
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
gridView.setAdapter(imgAdapter);
}
};
task.execute();
}
This class causing me android.os.NetworkOnMainThreadException,i know that i have to use asyncTask to make it but i can't figure out how because i am using 1 fragments and this make my application very slow especially when i laod bitmaps, can any one help me please.
public class ContainerData {
static public Context context;
public ContainerData() {
}
public static ArrayList<Feed> getFeeds(String feedurl){
SAXParserFactory fabrique = SAXParserFactory.newInstance();
SAXParser parseur = null;
ArrayList<Feed> feeds = null;
try {
parseur = fabrique.newSAXParser();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
URL url = null;
try {
url = new URL(feedurl);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
DefaultHandler handler = new ParserXMLHandler();
try {
parseur.parse(url.openConnection().getInputStream(), handler);
feeds = ((ParserXMLHandler) handler).getData();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return feeds;
}
}
If you use AsyncTask make sure getFeeds is called inside the doInBackground(...) callback
Regardless of whether you use a fragment or not, you're still trying to perform Network activity on the main thread.
Create a generic class that extends AsyncTask which can perform all your parsing.
public class MyTaskHandler extends AsyncTask<String, Integer, Boolean>
{
#Override
protected void onPreExecute()
{
//Could display progress dialog here
}
#Override
protected Boolean doInBackground(String... params)
{
//Implement your parser here
}
#Override
protected void onPostExecute(Boolean result)
{
//Check result, dismiss dialog etc
}
}
Then create a new instance of MyTaskHandler and run it...
MyTaskHandler myTask = new MyTaskHandler();
myTask.execute("http://www.myxmlsite.com/lists.xml");
The execute method can take (String... params) so you can pass for example a URL,and retrieve it in doInBackground(String... params)
#Override
protected Boolean doInBackground(String... params)
{
//Implement your parser here
String urlToParse = params[0];
}
Best of luck.