Android Studio - NetworkOnMainThreadException in object constructor - android

I get a error of NetworkOnMainThreadException in the line of AVObject brandObj = query.getFirst(); After did some searches about the error, I think I should use something like Asynctask. But couldn't figure out how to do it.
AVObject is same as ParseObject
public class Product {
Product(AVObject object) {
try {
AVObject brandObj = query.getFirst(); // this one is making network request
} catch (AVException e) {
e.printStackTrace();
}
}
}
Should I extends AsyncTask<AVObject, Void, AVObject>
Then
#Override
protected AVObject doInBackground(AVObject... objects) {
return null;
}
But not sure what should I write in doInBackground
Any suggestions?

NetworkOnMainThreadException is thrown when an application attempts to
perform a networking operation on its main thread. This is only thrown
for applications targeting the Honeycomb SDK or higher.
You cannot perform any networking on your main thread because it may block the UI. Hence, you should do everything in a separate thread.
AsyncTask is one of the easier solutions. Setup your AsyncTask (follow some tutorials/guides) and put your networking code into doInBackground() method, which runs on a separate thread.

Ideally, an object's constructor does not perform disk I/O or network I/O. In your case, it does.
So, every piece of code that is calling new Product(...) needs to be put into a background thread (plain thread, RxJava chain, JobIntentService, AsyncTask, etc.). Product itself would not change.

Related

join() method doesn't waits for thread to end

I have an AsyncTask, and in its doInBackground method I call a method in another class:
#Override
protected ArrayList<CustomClass> doInBackground(ArrayList<CustomClass>... array) {
ArrayList<CustomClass> retorno= DataNetwork.GetCustomClassArrayList(array[0],(...more parameters...));
return retorno;
}
In DataNetwork I have that method, which does a REST call, and returns a result. I am forced to use a library that makes the REST call (I think it uses Volley, but I am not sure. To call this library, I have to make an Intent, which is passed to the method makeRESTCall):
public static ArrayList<CustomClass> GetCustomClassArrayList(various params goes here){
ArrayList<CustomClass> toReturn;
//some parameters processing
library.makeRESTCall(Intent intent){
//processing the answer
toReturn=processAnswerJSONResponse();
}
return toReturn;
}
This way, I get to the return toReturn line, before answer from REST is processed. So, I tried to make a Thread, and use the join statement. The GetCustomClassArrayList method (well, most of it, until the t.start()) is now inside a Thread. The end of the method is now:
(...)
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return toReturn;
The execution calls t.join() immediately after t.start(); and toReturn is null.
Maybe is a noob question, but using the method join() always worked for me, and waited for the thread to finish before entering the return statement. No exception, no error. It just doesn't wait for the thread to finish.
Why is not working now? What can I do to wait for the toReturn variable to be fulfilled before entering the return statement?
Thank you.
The problem likely stems from using a library which is already returning the response asynchronously, so your AsyncTask is not blocking. Check the library documentation.
AsyncTask is not like a normal thread. It is specialized to execute one time, blocking if necessary in the doInBackground method, then returning results to be handled in the main thread. If your 3rd party REST library has a synchronous version of it's calls, you could use that in your AsyncTask, but it will likely be less efficient than the library's built in functionality.

Multiple aynchronous network calls blocking main thread because their output at same time?

I am using priority job queue , there are number of jobs running in parallel, so that their result populates on UI at same time which takes application to ANR, is there any way , so that i can run asynchronous calls and populate ui synchronously?
UI is always populated synchronously, if it is done in correct way. The correct way is to call activity.runOnUiThread(Runnable), directly or indirectly. Seems that your problem is that your jobs post to UI thread in a too high rate.
First, check if the Runnables to update UI does only UI work. Any calculations should be done outside the UI thread. If it is so, create an intermediate object which makes pauses between UI updates from the parallel jobs and so lets the UI thread to respond to updates from user. It can look as follows:
public class PauseMaker {
Semaphore sem = new Semaphore(1);
public void runOnUiThread(Runnable r) {
sem.aquire();
Thread.sleep(1);
activity.runOnUiThread(new Runnable(){
try {
r();
} finally {
sem.release();
}
});
}
}
You can use the zip operator of rxjava2 to merge the responses together and when the combined response comes you can populate the UI synchronously .. for reference you can check..
http://www.codexpedia.com/android/rxjava-2-zip-operator-example-in-android/
Note The zipper will the return merged response after all the responses are received

Best practice for repeated network tasks?

I have a small Android application in which I need to do some FTP stuff every couple of seconds.
After learning the hard way that running network stuff on the UI thread is something Android does not really like, I've come to this solution:
// This class gets declared inside my Activity
private class CheckFtpTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... dummy) {
Thread.currentThread().setName("CheckFtpTask");
// Here I'll do the FTP stuff
ftpStuff();
return null;
}
}
// Member variables inside my activity
private Handler checkFtpHandler;
private Runnable checkFtpRunnable;
// I set up the task later in some of my Activitiy's method:
checkFtpHandler = new Handler();
checkFtpRunnable = new Runnable() {
#Override
public void run() {
new CheckFtpTask().execute((Void[])null);
checkFtpHandler.postDelayed(checkFtpRunnable, 5000);
}
};
checkFtpRunnable.run();
Is this good practice to perform a recurring task that cannot run on the UI thread directly?
Furthermore, instead of creating a new AsyncTask object all the time by calling
new CheckFtpTask().execute((Void[])null);
would it be an option to create the CheckFtpTask object once and then reuse it?
Or will that give me side effects?
Thanks in advance,
Jens.
would it be an option to create the CheckFtpTask object once and then reuse it? Or will that give me side effects?
No, there will be side-effects. Quoting the docs Threading Rules:
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
You will just need to create a separate instance of the task each time you want to run it.
And I'm not sure why you need the Runnable or Handler. AsyncTask has methods that run on the UI Thread (all but doInBackground(), actually) if you need to update the UI.
Check this answer if you need a callback to update the UI when the task has finished.
You should create a new Async task for every call.
See the Android Documentation: AsyncTask. According to this documentation:
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Specifically check out the threading rules section. There is a similar answer here, https://stackoverflow.com/a/18547396/2728623
Java ThreadPools and the ExecutorFramework allows you to execute threads as needed and reduces thread creation overhead. Check out the singleThreadExecutor. The thread pool usage is pretty easy too!

Best practice for threaded getter method

I also faced with the NetworkOnMainThreadException in my application but I don't see how to resolve it.
I have a class with a getter method. Like:
public ArrayList<News> get(int i){
// get the list of news from a HTML on the net. The news are split up into web pages on the site
// and i is the page number
return NewsParser(i);
}
Since Android throws the exception I come up with an idea of a downloader class which downloads the HTML content in a separate thread
pubic ArrayList<News> get(int i){
Downloader dl = new Downloader(i);
String HTMLcontent = dl.getContent(); <-- AsyncTask starts in getContent()
return NewsParser(HTMLcontent); <-- What happens here in the main thread???
}
Any ideas/best practices for this problem?
Just looking at your code and your question, it seems like you don't have a very solid understanding of how AsyncTask (or threads in general) works.
I would recommend reading this article.
Basically, your AsyncTask should query the web URL and download the data. Once the data is complete, your AsyncTask should send the HTMLContent to a handler object. The handler will be running on your main thread, so you can display the information to the user at that point.
You shouldn't be calling
dl.getContent();
to retrieve the content. AsyncTask runs on a separate thread, so you can't just call methods like this from your main thread. You need to create the Downloader object (like you did) and then call
dl.execute();
to start the AsyncTask.
run the get method inside a thread,
new Thread(new Runnable() {
#Override
public void run() {
// call get method here
}
}).start();
Since Honeycomb (Android 3.0) you can't use Networking Operations in the MainThread to avoid freezes on the Phone. This is important in order to make your app responsive.
More info:
NetworkOnMainThreadException
Responsiveness

Thread handling problem in Android Junit Test Case

I am implementing a testcase in Android Juint. I am facing problem in
handling threads. After the successful running of a test case, it will
not wait for child thread to be finished. e.g. If one testcase call
some services in server. testcase will successfully send request to a
server, but it will not wait for a response. Because testcase will
start this request in a different Thread. Currently I am using
following code,
currentThread = Thread.currentThread();
synchronized (Thread.currentThread()) {
try {
Thread.currentThread().wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
After getting response I am using the following code to start the
current thread again.
currentThread.interrupt();
I think this is not the good way to do it. There must be a some other
technique to handle this problem properly. Please let me know as soon
as possible if any one knows solution for this.
Thanks,
Vashishta
In your code the synchronized block never blocks (wait for another thread), because you synchronize on Thread.currentThread() which is a different object in different threads.
You have so synchronize on an object common to all threads: typically an object that contains shared data. Then you synchronize{..} a block od code that manipulates this data.

Categories

Resources