Network-related tasks on a separate thread

早过忘川 提交于 2020-01-25 10:24:27

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!