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
Related
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.
I have this piece of code running on Thread, for Android device. It was initially sufficient, but now I have a change in requirements that requires me to return the result after a HTTP POST. The "POST" function is in another class, so the code below will not work.
I read that RunnableFuture allows extraction of results for return of result. Can someone guide me on how to change this piece of code to that?
public ArrayList<String> addfood(final String status, final String spaceId) {
Log.d(TAG, "Add Food");
final ArrayList<String> results = new ArrayList<>();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
String cookie = android.webkit.CookieManager.getInstance().getCookie(sURL);
Uri.Builder builder = new Uri.Builder()
.appendQueryParameter(“status”,status)
.appendQueryParameter("cookie", cookie)
.appendQueryParameter("space", spaceId);
String addresult = foodpost(POST(url, builder));
results.add(addresult);
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
return results;
}
let me clarify you a pair of things:
Analyzing your piece of code you're trying to access to another method of other class (as you said in your comment) from inside of one thread:
The "POST" function is in another class, so the code below will not work
It doesn't work because you have to have a reference to the other object in order to use the method.
But let me ask you a couple of things:
Concurrency is hard (very hard). Even if after modifying your piece of code to use properly the POST method, have you ever considered what happens with that thread? What happens when the user decides to rotate the device? What happens when your UiThread (the thread responsible of updating all UI elements of your application) decides to read that list of resutls (is thread safe also?)? I mean there are a lot of considerations to take care before creating a thread to do some background operation. And trust me, is very easy to do things wrong. Maybe it can leak memory and your app may become an unresponsive one. Do you think is neccesary?
There are a lot of libraries that can help you to achieve that network request in a easy manner, carrying the weight of doing background things for you. Those libraries are very battle tested, it has a decent amount of user base. Libraries like Retrofit or Volley are very good options to do whatever thing you want to achieve. So is there a need for not using that?
Sorry if I discourage you to use the thread, but there are a lot of useful options that would help you in the long run.
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!
Ok, I have read a lot of questions here on StackOverflow but i still can't understand so i'm opening a new question.
I made a class which function connects to internet and fetches json as string. It works fine in normal Java Application but i can't get it work in my android project.
I'm getting next error: android.os.NetworkOnMainThreadException
So to my understanding I have to use AsyncTask but I don't know how to wrap my function into it.
Function looks like this:
public static String get(String url){
//connect and get data to string
// return string
}
Like I said it works fine in normal JavaApplication but not in android project.
Thx for help!
http://developer.android.com/reference/android/os/AsyncTask.html
Look at the sample
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
}
Your "get" function must be splitted into 2 separate function in this class
what you want to get in, put in
doInBackground
And what you want to do with data which you receive into
onPostExecute
As I understand you use AndroidHttpClient -> so you can not even try to perform your network operations in the UI thread - > so create separate thread for this purpose. You can either use AsynchTask, Thread + Handler or HandlerThread for this purpose, or you can try to experiment here with java.util.concurrent package.
NetworkOnMainThreadException | Android Developers
developer.android.com/... -
Class Overview. The exception that is thrown when an application attempts to perform a networking operation on its main thread. This is only thrown for ...
You can create the thread method which extends AsyncTask (as you correctly understood), and execute it with .execute().
Exactly how you set it up is up to you. Here's a link with a tutorial on spinning these threads:
http://www.vogella.com/articles/AndroidPerformance/article.html#concurrency_threads
I sent "Scores Activity" to doinbackground then run a function on Scores Activity but getting
"Only the original thread that created a view hierarchy can touch its views." on "birinci.setText(txt);" line.
what am I missing here looks using same context?
Scores Activity
{
Object[] stuff = {this.dhn, Scores.this};
ConnectXML runXML = new ConnectXML();
runXML.execute(stuff);
}
public void setScoreListUpdate(String txt)
{
birinci.setText(txt);
}
private Scores myScores;
protected String doInBackground(Object... arguments) {
myScores = (Scores)stuff[1];
myScores.setScoreListUpdate(result);
}
The error message already gives the answer: you can't touch (edit/modify/update/etc.) any views from a thread that did not create them. Since anything that is executed in the doInBackgrund(...) of an AsyncTask is done by a separate thread, you can't do any direct view manipulations in there.
The solution is quite simple: override the other methods an AsyncTask provides, depending on your needs. If you're trying to update a view after all work is done, simply override onPostExecute(...). If you want to indicate some sort of progress while the work is being done in the background, use onProgressUpdate(...). Everything in there is being executed by the main UI thread (which created all views).
Please have read through the documentation on AsyncTask, since that describes the different steps and possibilities quite clearly.