单独线程上的网络相关任务

时间:2014-05-31 18:30:42

标签: java android multithreading

我目前有一个Pollen类,它是我编写的一个类,它使用JSoup库来解析HTML。此处还显示了我的PlaceholderFragment类。

    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;
        }
    }

这是我的Pollen课程。

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();
        }
    }
}

我在尝试失败的过程中学到了很多东西。我发现,在Pollen中调用我的onClick类时,我正在做一项昂贵的任务。因此,我应该把它放在一个单独的线程中。要添加,因为我在main / UI线程中调用我的Pollen类,它会导致我的应用程序崩溃。

我咨询了Stackoverflow这个问题,帮助我尝试解决我的问题:How to fix android.os.NetworkOnMainThreadException?

我通过这个来自logcat的错误日志发现了我的错误和解决方案,特别是NetworkOnMainThread,其中Android显然阻止我在我的UI线程上做任何网络。

我的问题是 - 如何将我的Pollen类分配到不属于我的UI类的单独线程中?

enter image description here

继续我关于Stackoverflow线程的教程,我添加了这个类。我不知道我在做什么......但我会尽力继续:

abstract class RetrievePollenTask extends AsyncTask<Integer, Void, Pollen>
{

    protected Pollen doInBackground(String... params)
    {
        // TODO Auto-generated method stub
        return null;
    }

}

5 个答案:

答案 0 :(得分:1)

是的,您正在尝试在UI线程内部进行网络连接,这是非法的并且会捕获NetworkOnMainThreadException的异常。

您可以使用正在执行的AsyncTask而不是在主线程内部连接,但它不应该是抽象的,它只是一个普通的类,因此您可以执行AsyncTask ..

示例:

    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());
     }

}

你可以使你的asynctask成为你片段的内部类,所以你不需要在它上面传递context参数。也不要更新任何视图insidte doInBackground因为它是一个不同的线程,它将捕获异常。

答案 1 :(得分:0)

这是AsyncTask的{​​{3}}。您必须使用AsyncTask执行所有网络操作。 它基本上有3种方法

  • onPreExecute()
  • doInBackground()
  • onPostExecute()

使用doInBackground()方法执行网络操作。更新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());
    }

}

PlacholderFragment班级

button.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                RetrievePollenTask object = new RetrievePollenTask();
                object.execute(19104);
            }
        });

答案 2 :(得分:0)

AsyncTask是Android框架提供的一种机制,可以在不阻塞主UI线程的情况下方便执行长时间运行的任务。阅读Android开发者网站上的Keeping Your Apps Responsive教程,了解有关此主题的详细信息。

提供的

This链接可帮助您使用AsyncTask机制重新设计课程。

希望这有帮助

答案 3 :(得分:0)

AsyncTask用于在非UI线程中运行代码,但也有可与您的UI交互的方法。

AsyncTask<String, Integer, Pollen>
这定义了AsyncTask使用的对象。如果不使用任何对象,请使用Void

  • 第一个是doInBackground()的输入。
  • 第二个是onProgressUpdate()用于定期更新用户进度的参数
  • 最后一个是从doInBackground()
  • 返回的结果

这些参数声明为Object... vars,实际上是您可以使用vars[index]访问的数组。如果您只传递一个变量,请使用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.
    }
}

答案 4 :(得分:0)

经验法则:

  • 网络(或其他I / O或长期运行)代码进入doInBackground(),在后台线程中执行。
  • UI代码进入onPostExecute(),一旦后台操作完成,就会在UI线程中执行。

在您的示例中,这可能是您可以编写的最简单的代码:

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);
    }
});