问题
I currently have a Pollen class which is a class I wrote which uses the JSoup library to parse HTML. Also shown here is my PlaceholderFragment
class.
public static class PlaceholderFragment extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
final Button button = (Button) rootView.findViewById(R.id.button1);
final TextView textview = (TextView) rootView.findViewById(R.id.textview1);
button.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Pollen pollenObject = new Pollen(19104);
textview.setText(pollenObject.getCity());
}
});
return rootView;
}
}
Here is my Pollen class.
public static class Pollen
{
@SuppressLint("SimpleDateFormat")
public Pollen(int zipcode)
{
this.zipcode = zipcode;
Document doc;
try
{
// pass address to
doc = Jsoup.connect("http://www.wunderground.com/DisplayPollen.asp?Zipcode=" + this.zipcode).get();
// get "location" from XML
Element location = doc.select("div.columns").first();
this.location = location.text();
// get "pollen type" from XML
Element pollenType = doc.select("div.panel h3").first();
this.pollenType = pollenType.text();
SimpleDateFormat format = new SimpleDateFormat("EEE MMMM dd, yyyy");
// add the four items of pollen and dates
// to its respective list
for(int i = 0; i < 4; i++)
{
Element dates = doc.select("td.text-center.even-four").get(i);
Element levels = doc.select("td.levels").get(i);
try
{
pollenMap.put(format.parse(dates.text()), levels.text());
}
catch (ParseException e)
{
e.printStackTrace();
}
}
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I learned a lot while failing every attempt. I discovered that, in my use of calling my Pollen
class within onClick
, I am doing an expensive task. Thus, I should put it in a separate thread. To add, since I am calling my Pollen
class within my main/UI thread, it causes my app to crash.
I consulted this Stackoverflow question in aiding my attempt to solve my issue: How to fix android.os.NetworkOnMainThreadException?
I discovered my error and solution via this error log from logcat, specifically, NetworkOnMainThread
where Android explicitly prevents me from doing anything network on my UI thread.
My question is - how do I allocate my Pollen
class into a separate thread that is not in my UI class?

Continuing my tutorial on that Stackoverflow thread, I have added this class. I have no idea what I am doing.. But I will try my best to continue:
abstract class RetrievePollenTask extends AsyncTask<Integer, Void, Pollen>
{
protected Pollen doInBackground(String... params)
{
// TODO Auto-generated method stub
return null;
}
}
回答1:
Yes you are trying to do networking inside the UI thread which is illegal and catch an exception which is NetworkOnMainThreadException
.
Instead of connecting inside the main thread you can use the AsyncTask
which you are doing right now but it shouldn't be abstract it is just a plain class so you can execute the AsyncTask
..
example:
public class RetrievePollenTask extends AsyncTask<Integer, Void, Pollen>
{
protected Pollen doInBackground(String... params)
{
Pollen pollenObject = new Pollen(19104);
return pollenObject;
}
protected void onPostExecute(Pollen result) {
textview.setText(pollenObject.getCity());
}
}
you can make your asynctask as an inner class of you fragment so you dont need to pass the context parameter on it. Also dont put update any view insidte the doInBackground
cause it is a different thread that it will catch an exception.
回答2:
AsyncTask
is a mechanism provided by the Android framework to facilitate execution of long running tasks without blocking the main UI thread. Read Keeping Your Apps Responsive tutorial on the Android Developer sites for a detailed treatment on this subject.
This link provided should help you re-design your classes using the AsyncTask
mechanism.
Hope this helps
回答3:
This is a tutorial of AsyncTask
. You have to do all the network operations using AsyncTask
.
It basically has 3 methods
onPreExecute()
doInBackground()
onPostExecute()
do the network operations in doInBackground()
method. update the UI in onPostExecute()
class RetrievePollenTask extends AsyncTask<Integer, Void, Pollen>
{
@Override
protected Pollen doInBackground(Integer zip)
{
// TODO Auto-generated method stub
Pollen pollenObject = new Pollen(zip);
return pollenObject;
}
@Override
protected void onPostExecute(Pollen pollenObject) {
textView.setText(pollenObject.getCity());
}
}
And inPlacholderFragment
class
button.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
RetrievePollenTask object = new RetrievePollenTask();
object.execute(19104);
}
});
回答4:
Rule of thumb:
- Network (or other I/O or long-running) code goes in
doInBackground()
, which is executed in a background thread. - UI code goes in
onPostExecute()
, which is executed o the UI thread as soon as the background operation is finished.
In your example, this is probably the simplest code you could write:
button.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
AsyncTask<Integer, Void, Pollen> loadPollen = new AsyncTask<Integer, Void, Pollen>()
{
@Override
protected Pollen doInBackground(Integer... params)
{
return new Pollen(params[0]);
}
@Override
protected void onPostExecute(Pollen result)
{
textview.setText(result.getCity());
}
};
loadPollen.execute(19104);
}
});
回答5:
An AsyncTask
is used to run code in a non UI thread but also has methods that can interact with your UI.
AsyncTask<String, Integer, Pollen>
This defines the Objects that the AsyncTask uses. Use Void
if no object is to be used.
- The first is an input for your
doInBackground()
. - The second is an argument for
onProgressUpdate()
to be used to periodically update the user on progress - The last is the result returned from
doInBackground()
These Arguments are declared with Object... vars
and are actually arrays that you would access with vars[index]
. If you only ever pass one variable access it with var[0]
Here is the official documentation
class RetrievePollenTask extends AsyncTask<String, Integer, Pollen>
{
@Override
protected void onPreExecute() {
// set up a ProgressBar or other UI action here *before* the task runs
}
@Override
protected Pollen doInBackground(String... params)
{
// perform your separate non UI thread actions here
// call publishProgress(int) to update your UI periodically
return pollenObject;
}
@Override
protected void onProgessUpdate(Integer... progress) {
// update your UI or ProgressBar
}
@Override
protected void onPostExectute(Pollen resultReturned)
// back to the UI thread again here to update Views or cancel your ProgressBar etc
// this executes *after* your task has completed
// it receives its argument from the return of doInBackground() so you can use that when updating your UI.
}
}
来源:https://stackoverflow.com/questions/23973612/network-related-tasks-on-a-separate-thread