3

I am making some RSS reader for some website, so I wanted to implement actionbar and viewpager on lower versions of Androd that 4.0, so I am using ActionBarSherlock and ViewPagerIndicator from Jake Wharton, so I am working with fragments.

And I want to read some RSS feed from URL, and I have AsyncTask class for that called LoadXMLData, and here is code of that class.

LoadXMLData class:

public class LoadXMLData extends AsyncTask<String, RSSFeed, RSSFeed>{


private ProgressDialog mProgressDialog;


private Context context;
RSSFeed feed;
private String RSSFEEDURL = "http://balkanandroid.com/feed/";

public LoadXMLData(Context context) {
    this.context = context;
    mProgressDialog = new ProgressDialog(context);
    mProgressDialog.setMessage("Molimo Vas, sačekajte. Podaci se učitavaju.");
}

@Override
protected void onPreExecute() {
    super.onPreExecute();
    mProgressDialog.show();
    Log.d("OVDE SAM:", "onPreExecute()");
}

@Override
protected RSSFeed doInBackground(String... urls) {
    // Obtain feed
    DOMParser myParser = new DOMParser();
    feed = myParser.parseXml(urls[0]);
    Log.d("OVDE SAM:", "PARSIRAM XML");
    return feed;
}



@Override
protected void onPostExecute(RSSFeed result) {
    mProgressDialog.dismiss();
    super.onPostExecute(result);
}

}

Also I have class MainActivity, which extends SherlockFragmentActivity.

public class MainActivity extends SherlockFragmentActivity {
BAFragmentAdapter mAdapter;
RSSFeed feed;
Application myApp;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Log.d("OVDE SAM:", "MAIN ACTIVITY");

    myApp = getApplication();



    mAdapter = new BAFragmentAdapter(getSupportFragmentManager());

    ViewPager pager = (ViewPager) findViewById(R.id.pager);
    pager.setAdapter(mAdapter);

    TabPageIndicator indicator = (TabPageIndicator) findViewById(R.id.indicator);
    indicator.setViewPager(pager);

}

public RSSFeed getFeed() {
    return feed;
}

public void setFeed(RSSFeed feed) {
    this.feed = feed;
}

And the most imporatnt I have few fragment classes (LatestFragments, PhonesFragments, TabletFragments, ApplicationFragments and so on), and on each fragments I have almost same code as shown below.

Here is the full code of LatestFragment:

public class LatestFragment extends Fragment {

GridView lv;
RSSFeed feed;
CustomListAdapter adapter;
private String RSSFEEDURL = "http://balkanandroid.com/feed/";

public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_najnovije, container,
            false);


    AsyncTask<String, RSSFeed, RSSFeed> xml = new LoadXMLData(getActivity())
            .execute(RSSFEEDURL);

    // AsyncTask<String, RSSFeed, RSSFeed> load = new
    // LoadXMLData(getActivity()).execute(RSSFEEDURL);

    try {
        feed = xml.get();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    lv = (GridView) view.findViewById(R.id.GridView1);

    // Set an Adapter to the ListView
    adapter = new CustomListAdapter();
    lv.setAdapter(adapter);

    // Set on item click listener to the ListView
    lv.setOnItemClickListener(new OnItemClickListener() {

        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {
            // actions to be performed when a list item clicked
            int pos = arg2;

            Bundle bundle = new Bundle();
            bundle.putSerializable("feed", feed);
            Intent intent = new Intent(getActivity(), DetailsActivity.class);
            intent.putExtras(bundle);
            intent.putExtra("pos", pos);
            startActivity(intent);

        }
    });

    return view;
}

@Override
public void onDestroy() {
    super.onDestroy();
    adapter.imageLoader.clearCache();
    adapter.notifyDataSetChanged();
}

class CustomListAdapter extends BaseAdapter {

    private LayoutInflater layoutInflater;
    public ImageLoader imageLoader;

    public CustomListAdapter() {

        layoutInflater = (LayoutInflater) getActivity().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
        imageLoader = new ImageLoader(getActivity().getApplicationContext());
    }

    public int getCount() {
        // TODO Auto-generated method stub
        // Set the total list item count
        return feed.getItemCount();
    }

    public Object getItem(int arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    public long getItemId(int arg0) {
        // TODO Auto-generated method stub
        return 0;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        // Inflate the item layout and set the views
        View listItem = convertView;
        int pos = position;
        if (listItem == null) {
            listItem = layoutInflater.inflate(R.layout.list_item, null);
        }

        // Initialize the views in the layout
        ImageView iv = (ImageView) listItem.findViewById(R.id.thumb);
        TextView tvTitle = (TextView) listItem.findViewById(R.id.title);
        TextView tvDate = (TextView) listItem.findViewById(R.id.tvDate);

        // Set the views in the layout
        imageLoader.DisplayImage(feed.getItem(pos).getImage(), iv);
        tvTitle.setText(feed.getItem(pos).getTitle());
        tvDate.setText(feed.getItem(pos).getDate());

        return listItem;
    }

}

}

As you can see I use AsyncTask class LoadXMLData to read data in doInBackground() method, and then I call that AsyncTask class under all fragment classes with this code, because I need result of RSSFeed, because I need that data to show it to user.

  AsyncTask<String, RSSFeed, RSSFeed> xml = new LoadXMLData(getActivity())
            .execute(RSSFEEDURL);   

    try {
        feed = xml.get();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

And it works, but when I click to open other view from view pager its slow, almost freezes my app, and I get this message with Logcat.

07-10 00:22:40.598: I/Choreographer(623): Skipped 316 frames! The application may be doing too much work on its main thread.

Zookey
  • 2,637
  • 13
  • 46
  • 80

1 Answers1

5

That is because you are calling get() on your AsyncTask, which blocks. Do not do this.

Instead, use your feed in onPostExecute() of the AsyncTask.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • I assumed it was because of that. Anyway, how I can get that feed from onPostExecute in one of my fragment classes? – Zookey Jul 09 '13 at 22:35
  • @Zookey: One way is to have the `AsyncTask` be an inner class of the fragment in question, and mark the fragment as `setRetainInstance(true)`. Then you can just call a method on the fragment from `onPostExecute()` as needed, with `setRetainInstance(true)` ensuring that your fragment remains intact during configuration changes. Or, start using some sort of message bus (`LocalBroadcastManager`, Square's Otto, greenrobot's EventBus, etc.) and send a message from `onPostExecute()` to be picked up by the fragment (if it is still around). – CommonsWare Jul 09 '13 at 22:42
  • That sounds complicated! :) Is there any good example on working with async task and fragments? – Zookey Jul 09 '13 at 22:46