I am getting the following errors:
09-13 06:27:02.268: E/AndroidRuntime(476): at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1961)
09-13 06:27:02.268: E/AndroidRuntime(476): at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:794)
09-13 06:27:02.268: E/AndroidRuntime(476): at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1315)
09-13 06:27:02.268: E/AndroidRuntime(476): at android.os.AsyncTask.execute(AsyncTask.java:394)
And below is my code:
private class DownloadVerses extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String resultString = "";
try {
boolean resultBoolean = Utils.downloadTurboVerseFile(params[0]);
if(resultBoolean){
int progressPercentage = Integer.parseInt(params[2].substring(0,params[2].indexOf(".")));
resultString = "Downloading: "+params[1];
}
else{
resultString = "ERROR Downloading: "+params[1];
this.doInBackground(params);
}
} catch (Exception e) {
Thread.interrupted();
String exceptionString = e.toString();
}
return resultString;
}
#Override
protected void onPostExecute(String result) {
if(result.contains("ERROR")){
downloading.setTextColor(Color.parseColor("#f05036"));
}
else{
downloading.setTextColor(Color.parseColor("#79a1ad"));
}
downloading.setText(result);
if(checkIfVersesDownloaded()){
downloadProgressBar.setVisibility(View.INVISIBLE);
downloading.setText("Verses Have Been Downloaded.");
homeButton.setEnabled(true);
homeButton.setVisibility(View.VISIBLE);
}
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
I am executing the code like this:
while(i < verseTitles.size()){
new DownloadVerses().execute(verseMp3s.get(i), verseTitles.get(i),progressString);
i++;
}
I am thinking there is probably a simple solution that involves adding some code to my DownloadVerses private class?
You cannot create a large number of AsyncTasks in a loop like that. You can create slightly more than 128 before you will get the error that you see.
Your options are:
Do not create individual tasks for each verse. For example, have one task that handles all verses.
Supply your own custom ThreadPoolExecutor that has a larger queue for pending tasks, and use that with executeOnExecutor() on AsyncTask.
Do not use AsyncTask at all, but something other background threading solution.
Related
I am writing a class in java which is going to fetch results from a MongoDB database and then return the results back to the main program. My code is as follows:
public Document[] search(Document query, String databaseName, String collectionName) {
Log.i(TAG, "Search query: " + query);
_mongoClient.getDatabase(databaseName).getCollection(collectionName).find(query).continueWith(
new Continuation<List<Document>, Object>() {
#Override
public Object then(#NonNull final Task<List<Document>> task) throws Exception {
if (!task.isSuccessful()) {
Log.e(TAG, "Failed to execute query");
} else {
if (task.getResult().size() == 0) {
Log.i(TAG, "Query failed to return any results");
return null;
}
results = new Document[task.getResult().size()];
for (Integer i = 0; i < task.getResult().size(); i++) {
results[i] = task.getResult().get(i);
Log.i("test", results[i].getString("username").toString());
}
}
return null;
}
});
return results;
}
The issue with my code is that it doesn't wait for the code inside the method for retrieving the database to run. Instead it jumps straight to the return statement.
I have tried using AsyncTask like this:
private class WaitForDB extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(context);
pd.setMessage("Please wait");
pd.setCancelable(false);
pd.show();
}
protected Void doInBackground(Void... params) {
Document query = new Document("username", "a");
_mongoClient.getDatabase("gapp").getCollection("parent").find(query).continueWith(
new Continuation<List<Document>, Object>() {
#Override
public Object then(#NonNull final Task<List<Document>> task) throws Exception {
if (!task.isSuccessful()) {
Log.e(TAG, "Failed to execute query");
} else {
if (task.getResult().size() == 0) {
Log.i(TAG, "Query failed to return any results");
return null;
}
results = new Document[task.getResult().size()];
for (Integer i = 0; i < task.getResult().size(); i++) {
results[i] = task.getResult().get(i);
Log.i("test", results[i].getString("username").toString());
}
}
return null;
}
});
return null;
}
#Override
protected void onPostExecute(Void result) {
if (pd.isShowing()) {
pd.dismiss();
}
}
}
However, this does not work either. So, I would like to know, is there a way for the program to wait until the data is retrieved from the database? And if yes, how?
I will appreciate any kind of help.
Thanks in advance.
The first code doesn't wait only because you wrote it that way. If you want to observe that, put more log statements outside of error conditions or where you are building the result list, as well as before the return statements. The result list will be built after the return results.
What you can do is pass the "continuation" through to the method as a parameter
public void search(Document query, String databaseName, String collectionName, Continuation<List<Document>, Object> continuation) {
Log.i(TAG, "Search query: " + query);
_mongoClient.getDatabase(databaseName)
.getCollection(collectionName)
.find(query)
.continueWith(continuation);
} //end method
And that's it for that method. Do your processing elsewhere where you need the documents
For example, rather than trying to make this a blocking call for results
Document[] documents = search(...);
// process documents
You need to invoke the function, which waits for results to be received, then executes the inner callback function
// Do not define documents here
search(query, database, collection,
new Continuation<List<Document>, Object>() {
#Override
public Object then(#NonNull final Task<List<Document>> task) throws Exception {
if (!task.isSuccessful()) {
Log.e(TAG, "Failed to execute query");
} else {
List<Document> documents = task.getResults();
// process documents
}
});
// if you did define documents outside this, it'll still be empty
If you want to reduce all this code just to get an actual Document array, you need to define your own interface, but this is the most flexible working solution without extra classes
I can download data using the downloadJSON class for 1 URL using the below code no problem, but I want to get another set of data so it can be displayed with the other. I've tried several different method but to no avail.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_json);
TextView textView = (TextView)findViewById(R.id.JSONTextView);
textView.setText("Downloading JSON!");
new downloadJSON().execute("www.exampleURL.com/data1");
//new downloadJSON().execute(url2??);
}
private class downloadJSON extends AsyncTask<String, String, String>
{
protected String doInBackground(String... args) {
String result = "";
String formattedResult = "";
try {
InputStream stream = (InputStream)new URL(args[0]).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line = "";
while (line != null) {
result += line;
line = reader.readLine();
}
JSONObject json = new JSONObject(result);
formattedResult = "Downloadable Puzzles\r\n--------------\r\n";
JSONArray puzzles = json.getJSONArray("PuzzleIndex");
for (int i = 0;i < puzzles.length(); ++i) {
formattedResult += puzzles.get(i) + "\r\n";
}
} catch (Exception e) {
e.printStackTrace();
}
return formattedResult;
}
protected void onPostExecute(String pResult) {
TextView textView = (TextView)findViewById(R.id.JSONTextView);
textView.setText(pResult);
}
}
Edit: my question is not a duplicate of the link posted below as my question has much more weight to it with the fact that JSON and URL's are involved. The link is in no way specific to my problem and doesn't help the question.
The Async task doesn't return the control to the calling method. It only runs the onPostExecute() in the main thread after completing the doInBackground() on a background thread.
One approach to transfer control back into calling method is to use interface.
public class DownloadJSON extends AsyncTask<String, String, String> {
private AsyncCallback mCallback;
public DownloadJSON(AsyncCallback callback) {
mCallback = callback;
}
protected String doInBackground(String... args) {
// process background task
}
protected void onPostExecute(String result) {
if (mCallback != null)
mCallback.onComplete(result);
}
public interface AsyncCallback {
void onComplete(String result);
}
}
And then start asynctask using
new DownloadJSON(new DownloadJSON.AsyncCallback() {
#Override
public void onComplete(String result) {
textView.setText(result);
}
}).execute("www.exampleURL.com/data1");
I can suggest you to abandon this old way of picking a thread from thread pool and execute this heavy operation at background thread
check out this awesome lib. RxJava
I am trying to make a synchronous request to the server using RequestFuture but it's not working . The same request when done using asynchronous works fine.
This is my code:
public void fetchModules(){
JSONObject response = null;
RequestQueue requestQueue = Volley.newRequestQueue(getContext());
RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(Url.ALL_MODULES_URL,null,future,future);
requestQueue.add(request);
try {
response = future.get(3, TimeUnit.SECONDS); // Blocks for at most 10 seconds.
} catch (InterruptedException e) {
Log.d(TAG,"interupted");
} catch (ExecutionException e) {
Log.d(TAG,"execution");
} catch (TimeoutException e) {
e.printStackTrace();
}
Log.d(TAG,response.toString());
}
I am getting a nullpointerexception:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String org.json.JSONObject.toString()' on a null object reference
at com.maths.app.AllModules.fetchModules(AllModules.java:85)
at com.maths.app.AllModules.onCreateView(AllModules.java:51)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2080)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1108)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1290)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1677)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:536)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
it's returning a null response. How can I solve this?
tl;dr;
You got deceived by the try-catch
Explanation:
Because the RequestFuture.get()is probably running on the UI thread you are really getting a java.util.concurrent.TimeoutException behind the scenes. That is the default behaviour when the calls gets executed on the main thread.
The try catch stops the app from crashing, nevertheless the response is still a null reference which crashes the app when you try to Logthe result.
If you comment the following line you will see that the app doesn't crash (there) anymore.
Log.d(TAG,response.toString());
Fix: Making the RequestFuture network call on another thread!
One way to do it:
public class TestVolley {
private String TAG = "SO_TEST";
private String url = "http://pokeapi.co/api/v2/pokemon-form/1/";
public JSONObject fetchModules(Context ctx){
JSONObject response = null;
RequestQueue requestQueue = Volley.newRequestQueue(ctx);
RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(url,null,future,future);
requestQueue.add(request);
try {
response = future.get(3, TimeUnit.SECONDS); // Blocks for at most 10 seconds.
} catch (InterruptedException e) {
Log.d(TAG,"interrupted");
} catch (ExecutionException e) {
Log.d(TAG,"execution");
} catch (TimeoutException e) {
e.printStackTrace();
}
Log.d(TAG,response.toString());
return response;
}
}
The AsyncTask which will make the network call :
public class MyVolleyAsyncTask extends AsyncTask<String,String, JSONObject> {
private Context ctx;
public MyVolleyAsyncTask(Context hostContext)
{
ctx = hostContext;
}
#Override
protected JSONObject doInBackground(String... params) {
// Method runs on a separate thread, make all the network calls you need
TestVolley tester = new TestVolley();
return tester.fetchModules(ctx);
}
#Override
protected void onPostExecute(JSONObject result)
{
// runs on the UI thread
// do something with the result
}
}
Main Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// this is your old code which will crash the app
//TestVolley tester = new TestVolley();
//tester.fetchModules(this);
// Works!
new MyVolleyAsyncTask(this).execute();
}
}
result:
com.so.henriquems.testvolleyfuture D/SO_TEST: {"id":1,"pokemon":{"url":"http:\/\/pokeapi.co\/api\/v2\/pokemon\/1\/","name":"bulbasaur"},[...]
Hope this helps
cheers!
We can use RxJava.
Lets assume that the fetchModules method returns JSONObject
Observable<JSONObject> moduleObservable = Observable.defer(new Callable<ObservableSource<? extends JSONObject>>() {
#Override
public ObservableSource<? extends JSONObject> call() throws Exception {
return Observable.just(fetchModules());
}
});
In MainActivity
moduleObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.Observer<JSONObject>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(JSONObject response) {
// Your response is here
}
#Override
public void onError(Throwable e) {
showAlert(context, e.getMessage());
}
#Override
public void onComplete() {
}
});
After researching this question myself, you CAN'T (at the moment of writing) do it in the main thread
I want Volley to do it in the main thread because I need to block until Volley finish getting response. And this is not possible, synchronous request on Volley must be in an async thread, not in the main thread.
The work around that I have done is, doing the subsequent codes inside the onResponse method of Volley request
I have call the GetXMLTask from my service and it will repeatedly call every 1 seconds to get data from the IP address (MyIP).
MyService.java
public class MyService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
if (GlobalFunctions.isInternetAvailable(MyService.this)
|| GlobalFunctions.isWifi(MyService.this)) {
MyTimerTask myTask = new MyTimerTask();
Timer myTimer = new Timer();
myTimer.schedule(myTask, 1000, 1000);
} else {
Toast.makeText(MyService.this, "No Internet Connection", 1000).show();
}
return Service.START_STICKY;
}
class MyTimerTask extends TimerTask {
public void run() {
GetXMLTask task = new GetXMLTask();
task.execute(new String[] { MyIP });
}
}
}
asynctask is use in the GetXMLTask.java.
public class GetXMLTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
String output = null;
for (String url : urls) {
output = getOutputFromUrl(url);
}
return output;
} catch (Exception e) {
return null;
}
}
}
and now when the apps is running, i have change the ip address, but the "urls" still showing the previous ip address (see the data from eclipse debug mode) and it the "urls" will be updated after quite a long time.
May i know what should i do so that urls in the asynctask can directly take newest ip address without long delay.
thank you so much
Updated 24/4/2014:
I have make changes for the doinBackground code, but the data received from the IP address is still not the updated data.
protected String doInBackground(String... urls) {
try {
String output = null;
String[] newurl = {GlobalVariables.Global_URL + "/status.xml"};
for (String url : newurl) {
output = getOutputFromUrl(url);
}
return output;
} catch (Exception e) {
return null;
}
}
Any idea? Thank You
Updated 25/4/2014:
I have debug the code and notice that when IP address is changed, the asynctask seem like freeze for quite a long time. I have put the break point in the doinbackground, and it doesn't go in.
Any idea? thank you
The for loop in doInBackground is processing urls sequentially. You may need to check for change in ip inside for loop and if ip has changed do the needful (for example updating urls accordingly).
i am developing application in which i am checking availability of port before reading and writing on socket. i am using following code to check status
private boolean isAvailable(String host, int port) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(host, port), 1000);
isPortAvailable = socket.isConnected();
} catch (IOException e) {
isPortAvailable = false;
}
return isPortAvailable;
}
After this i am checking this status on onClick()
if (isAvailable(ip, Integer.parseInt(portLVR))) {
startActivity(new Intent(getApplicationContext(),ActivityLivingRoom.class));
} else
Toast.makeText(getApplicationContext(),"Connection Error !", Toast.LENGTH_SHORT).show();
but my problem is if i check this status on main thread then android will give me networkonMainThradException so how do i manage this operation using background thread?
Try this
private class SocketCheckTask extends AsyncTask<String , Integer , Boolean> {
String classname="";
public SocketCheckTask (String classname) {
this.classname=classname;
}
#Override
protected Boolean doInBackground(String... params) {
return isAvailable(params[0], Integer.parseInt(params[1]);
}
#Override
protected void onPostExecute(Boolean isAvailable) {
if (isAvailable)) {
Class c=Class.forName("yourpackage"+classname);
startActivity(new Intent(getApplicationContext(),c));
} else
Toast.makeText(getApplicationContext(),"Connection Error !", Toast.LENGTH_SHORT).show();
}
}
And send it like this
SocketCheckTask task=new SocketCheckTask ("ActivityLivingRoom");
task.execute(ipadress,port);
I think best solution would be, start a new thread on click event and putting your start activity code inside the same thread.
If you are using toast you can do it from that thread but if you plan to update UI (like red/green status) you have to use handler and messages.
FYI, Asynctask just remove the implementation of Thread and shows people a nice abstraction.
Like this:
private class CheckAvailabilityTask extends AsyncTask<Void, Void, Boolean> {
String ip;
int port;
public CheckAvailabilityTask(String ip, int port) {
this.ip = ip;
this.port = port;
}
#Override
protected Boolean doInBackground(Void... params) {
return isAvailable(this.ip, this.port);
}
#Override
protected void onPostExecute(Boolean isAvailable) {
if (iisAvailable) {
startActivity(new Intent(getApplicationContext(),ActivityLivingRoom.class));
} else
Toast.makeText(getApplicationContext(),"Connection Error !", Toast.LENGTH_SHORT).show();
}
}
And in onClick() event:
new CheckAvailabilityTask(IP, PORT).execute();
You can't open a socket and never close it just to establish whether a host:port is available.
The only real way to test whether any service or resource is available is to try to use it.
Just do the connect, and the I/O, when you need to do them, and handle the resulting exceptions at that point. You have to catch them anyway.
Don't write code that tries to predict the future.