Android: Implementing a pause until RSS feed is pulled from site
Question
So, I've built an Ok RSS reader for a new sports app I'll be releasing soon. It will read feeds from various sports sites and display them. The problem I have is that the feeds are loading immediately on the start of an activity which requires an internet connection.
If an internet connection goes down or there is latency, the app will sometimes hang and/or force close on me. I need something pause the screen until the feed contents have been pulled from the various XML feeds.
Many news apps and other RSS readers do this when you click on a new news category. You'll get an animated "updating" or "loading" dialogue. Here is my current code.
public class MyActivity extends ListActivity implements OnClickListener {
Button btn1;
Button btn2;
Button btn3;
Button btn4;
WebView webview;
TextView feedTitle;
TextView feedDescribtion;
TextView feedPubdate;
TextView feedLink;
private RSSFeed myRssFeed = null;
public class MyCustomAdapter extends ArrayAdapter<RSSItem> {
public MyCustomAdapter(Context context, int textViewResourceId,
List<RSSItem> list) {
super(context, textViewResourceId, list);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
//return super.getView(position, convertView, parent);
View row = convertView;
if(row==null){
LayoutInflater inflater=getLayoutInflater();
row=inflater.inflate(R.layout.row, parent, false);
}
TextView listTitle=(TextView)row.findViewById(R.id.listtitle);
listTitle.setText(myRssFeed.getList().get(position).getTitle());
TextView listTitle2=(TextView)row.findViewById(R.id.listtitle2);
listTitle2.setText(myRssFeed.getTitle());
TextView listPubdate=(TextView)row.findViewById(R.id.listpubdate);
String str = (myRssFeed.getList().get(position).getPubdate());
SimpleDateFormat inputFormatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z"); //please notice the capital M
SimpleDateFormat outputFormatter = new SimpleDateFormat("MM/dd/yyyy");
try {
Date date = inputFormatter.parse(str);
String text = outputFormatter.format(date);
listPubdate.setText(text);
} catch (ParseException e ) {
e.printStackTrace();
}
return row;
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hawkcentral);
btn1 = (Button) findViewById(R.id.hawknation_button);
btn1.setOnClickListener(this);
btn2 = (Button) findViewById(R.id.hawkcentral_button);
btn2 .setOnClickListener(this);
btn3 = (Button) findViewById(R.id.hawkeyesports_button);
btn3 .setOnClickListener(this);
espn = (Button) findViewById(R.id.espn_button);
feedTitle = (TextView)findViewById(R.id.feedtitle);
feedDescribtion = (TextView)findViewById(R.id.feeddescribtion);
feedPubdate = (TextView)findViewById(R.id.feedpubDate);
feedLink = (TextView)findViewById(R.id.feedlink);
readRss();
}
private void readRss(){
feedTitle.setText("--- wait ---");
feedDescribtion.setText("");
feedPubdate.setText("");
feedLink.setText("");
setListAdapter(null);
Toast.makeText(this, "Reading RSS, Please wait.", Toast.LENGTH_LONG).show();
try {
URL rssUrl = new URL("http://www.sports.com/feed");
SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
XMLReader myXMLReader = mySAXParser.getXMLReader();
RSSHandler myRSSHandler = new RSSHandler();
myXMLReader.setContentHandler(myRSSHandler);
InputSource myInputSource = new InputSource(rssUrl.openStream());
myXMLReader.parse(myInputSource);
myRssFeed = myRSSHandler.getFeed();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (myRssFeed!=null)
{
TextView feedTitle = (TextView)findViewById(R.id.feedtitle);
TextView feedDescribtion = (TextView)findViewById(R.id.feeddescribtion);
TextView feedPubdate = (TextView)findViewById(R.id.feedpubDate);
TextView feedLink = (TextView)findViewById(R.id.feedlink);
feedTitle.setText(myRssFeed.getTitle());
feedDescribtion.setText(myRssFeed.getDescription());
feedPubdate.setText(myRssFeed.getPubdate());
feedLink.setText(myRssFeed.getLink());
MyCustomAdapter adapter =
new MyCustomAdapter(this, R.layout.row, myRssFeed.getList());
setListAdapter(adapter);
}
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
Intent intent = new Intent(this,HawkCentralDetails.class);
Bundle bundle = new Bundle();
bundle.putString("keyTitle", myRssFeed.getItem(position).getTitle());
bundle.putString("keyDescription", myRssFeed.getItem(position).getDescription());
bundle.putString("keyLink", myRssFeed.getItem(position).getLink());
bundle.putString("keyPubdate", myRssFeed.getItem(position).getPubdate());
intent.putExtras(bundle);
startActivity(intent);
}
Solution
You should try using the AsyncTask it will help follow the below link
http://developer.android.com/reference/android/os/AsyncTask.html
With AsyncTask you get to load the data in background and is displayed when loaded till the time you can display a ProgressDialog
OTHER TIPS
You need to call readRSS() in separate thread as oncreate comes with restriction on time it takes. You can use a thread to fetch rss and update the UI by putting it in UI thread or use async task
refer http://developer.android.com/resources/articles/painless-threading.html
Either you can use asynctask or use the following code which uses message queue to make sure that the content is shown to the user only when its loaded fully from the web request and since its running in a seperate thread the GUI is not paused as well: InputSource myInputSource;
public void sampleFunction()
{
progressDialog = ProgressDialog.show(this, "", "Getting data...");
new Thread() {
public void run() {
try {
//do the web request to get the feeds
myInputSource = new InputSource(rssUrl.openStream());
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
messageHandler.sendEmptyMessage(0);
// messageHandler.sendEmptyMessage(0);
}
}.start();
}
}
//inside the handler set the string array retrieved from the WS in sampleFunction to the adapter
private Handler messageHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
//here write the code to parse the value stored in myInputSource
}
};