我需要获取更多 RSS Feed 的提要我必须聚合并按降序显示新闻的网址。
有些链接没有 xml <category> 的标签所以我需要创建一个:我必须知道提要来自哪里,以便我可以对它们进行分类。
这就是我要实现的目标:(对于 Source n 我指的是类别)
[![在此处输入图片描述][1]][1]
我曾经使用 Yahoo!Pipes进行所有这些更改。
我的尝试是创建一个 CustomListView对于每个 url,然后执行 AsyncTasks一次全部但无法正常工作 - 提要未按升序显示。
主 Activity
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
private RSSFeed myRssFeed = null;
String[] urlFeed = {"url1", "url2"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
for (int i = 0; i < urlFeed.length; i++) {
News news = new News(i);
news.execute();
}
}
@Override
public void onRefresh() {
for (int i = 0; i < urlFeed.length; i++) {
News news = new News(i);
news.execute();
}
}
private class News extends AsyncTask<Object, Void, Void> {
protected int number;
public News(int urlNumber) {
number = urlNumber;
}
@Override
protected Void doInBackground(Object... arg0) {
String data = "";
InputStream iStream;
try{
URL url = new URL(urlFeed[number]);
// Creating an http connection to communicate with url
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuilder sbf = new StringBuilder();
String line;
while( ( line = br.readLine()) != null){
sbf.append(line);
}
data = sbf.toString();
br.close();
SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
XMLReader myXMLReader = mySAXParser.getXMLReader();
RSSHandler myRSSHandler = new RSSHandler();
myXMLReader.setContentHandler(myRSSHandler);
InputSource myInputSource = new InputSource(url.openStream());
myXMLReader.parse(myInputSource);
myRssFeed = myRSSHandler.getFeed();
} catch (ParserConfigurationException | IOException | SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (myRssFeed != null) {
NestedListView list = (NestedListView)findViewById(android.R.id.list);
list.setVisibility(View.VISIBLE);
CustomList adapter = new CustomList(MainActivity.this, myRssFeed.getList());
adapter.addAll();
list.setAdapter(adapter);
} else
Toast.makeText(MainActivity.this, "Error",
Toast.LENGTH_LONG).show();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
}
RSSFeed
public class RSSFeed {
private String title = null;
private String description = null;
private String link = null;
private String pubdate = null;
private String image = null;
private String enclosure = null;
private String author = null;
private List<RSSItem> itemList;
RSSFeed(){
itemList = new Vector<RSSItem>(0);
}
void addItem(RSSItem item){
itemList.add(item);
}
RSSItem getItem(int location){
return itemList.get(location);
}
List<RSSItem> getList(){
return itemList;
}
}
RSSItem
public class RSSItem {
private String title = null;
private String description = null;
private String link = null;
private String pubdate = null;
private String image = null;
private String enclosure = null;
private String author = null;
}
自定义列表
public class CustomList extends ArrayAdapter<RSSItem> {
private static Activity context = null;
private final List<RSSItem> web;
public CustomList(Activity context, List<RSSItem> web) {
super(context, R.layout.new_listview, web);
CustomList.context = context;
this.web = web;
}
@SuppressLint("SetTextI18n")
@Override
public View getView(final int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
@SuppressLint({"ViewHolder", "InflateParams"}) final View rowView = inflater.inflate(R.layout.new_listview, null, true);
ImageView imageView = (ImageView)rowView.findViewById(R.id.image);
Picasso.with(context).load(web.get(position).getImage()).into(imageView);
TextView textView = (TextView)rowView.findViewById(R.id.title);
textView.setText(Html.fromHtml(web.get(position).getTitle()));
TextView textView1 = (TextView)rowView.findViewById(R.id.description);
textView1.setText(web.get(position).getDescription());
TextView textView2 = (TextView)rowView.findViewById(R.id.pubdate);
textView2.setText(pubdate);
return rowView;
}
}
RSSHandler
public class RSSHandler extends DefaultHandler {
final int state_unknown = 0;
final int state_title = 1;
final int state_description = 2;
final int state_link = 3;
final int state_pubdate = 4;
final int state_enclosure = 6;
final int state_image = 5;
final int state_author = 7;
int currentState = state_unknown;
String url;
RSSFeed feed;
RSSItem item;
boolean itemFound = false;
RSSHandler(){
}
RSSFeed getFeed(){
return feed;
}
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
feed = new RSSFeed();
item = new RSSItem();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
if (localName.equalsIgnoreCase("item")){
itemFound = true;
item = new RSSItem();
currentState = state_unknown;
}
else if (localName.equals("enclosure")) {
url = attributes.getValue("url");
currentState = state_image;
}
else if (localName.equalsIgnoreCase("title")){
currentState = state_title;
}
else if (localName.equalsIgnoreCase("description")){
currentState = state_description;
}
else if (localName.equalsIgnoreCase("link")){
currentState = state_link;
}
else if (localName.equalsIgnoreCase("pubdate")){
currentState = state_pubdate;
}
else if (localName.equalsIgnoreCase("author")){
currentState = state_author;
}
else{
currentState = state_unknown;
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
if (localName.equalsIgnoreCase("item")){
feed.addItem(item);
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
String strCharacters = new String(ch,start,length);
if (itemFound){
// "item" tag found, it's item's parameter
switch(currentState){
case state_enclosure:
item.setEnclosure(strCharacters);
break;
case state_title:
item.setTitle(strCharacters);
break;
case state_image:
item.setImage(url);
break;
case state_description:
item.setDescription(strCharacters);
break;
case state_link:
item.setLink(strCharacters);
break;
case state_pubdate:
item.setPubdate(strCharacters);
break;
case state_author:
item.setAuthor(strCharacters);
break;
default:
break;
}
}
else{
// not "item" tag found, it's feed's parameter
switch(currentState){
case state_enclosure:
feed.setEnclosure(strCharacters);
break;
case state_title:
feed.setTitle(strCharacters);
break;
case state_image:
feed.setImage(url);
break;
case state_description:
feed.setDescription(strCharacters);
break;
case state_link:
feed.setLink(strCharacters);
break;
case state_pubdate:
feed.setPubdate(strCharacters);
break;
case state_author:
feed.setAuthor(strCharacters);
break;
default:
break;
}
}
currentState = state_unknown;
}
最佳答案
该解决方案需要不止一处更改。您需要做的第一件事是让每个完成的新闻任务将其数据添加到一个大列表中。然后可以对该列表进行排序,这需要一个 Comparator。
您还需要一个名称列表,以显示在图像中称为 Source n 的占位符中,最后,为了比较它们,您需要将日期解析为实际日期。
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
private List<RSSItem> totalRssFeed = new ArrayList<>();
String[] urlFeed = {"MyURL", "MyUrl2", "MyUrl3"};
String[] names = {"Name", "Name2", "Name3"}
private CustomList adapter;
@Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
ListView list = (ListView) findViewById(android.R.id.list);
adapter = new CustomList(MainActivity.this);
list.setAdapter( adapter );
}
@Override
protected void onResume() {
// do this here and you dont need to repeat it in refresh and create
for (int i = 0; i < urlFeed.length; i++) {
News news = new News(i);
news.execute();
}
}
public class CustomList extends ArrayAdapter<RSSItem> {
...
public CustomList(Activity context) { //dont start with default data
super(context, R.layout.new_listview, null);
}
...
}
private class News extends AsyncTask<Object, Void, Void> {
protected int number;
public News(int urlNumber) {
number = urlNumber;
}
@Override
protected Void doInBackground(Object... arg0) {
try {
//no need to do the input stuff you were doing before here?
URL url = new URL(urlFeed[number]);
SAXParserFactory mySAXParserFactory = SAXParserFactory.newInstance();
SAXParser mySAXParser = mySAXParserFactory.newSAXParser();
XMLReader myXMLReader = mySAXParser.getXMLReader();
RSSHandler myRSSHandler = new RSSHandler(names[number]);
myXMLReader.setContentHandler(myRSSHandler);
InputSource myInputSource = new InputSource(url.openStream());
myXMLReader.parse(myInputSource);
totalRssFeed.addAll(myRSSHandler.getFeed());
Collections.sort(totalRssFeed);
} catch (ParserConfigurationException | IOException | SAXException e) { /* stuff */ }
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter.clear();
adapter.addAll(totalRssFeed);
}
}
public class RSSItem implements Comparable<RSSItem> {
public String tag;
public Date pubdate; //just public so i didnt need setters in this example
public RSSItem(String defaultTagToUse) {
//You should set the default to whatever you want displayed
//when the tag for <category> is missing, and just update it normally otherwise
tag = defaultTagToUse;
}
void setPubDate(Date date) {
pubdate = date;
}
...
@Override
public int compareTo(@NonNull RSSItem another) {
int res;
if (pubdate == null) {
if (another.pubdate == null) {
res = 0;
} else {
res = -1;
}
} else {
if (another.pubdate == null || pubdate.getTime() > another.pubdate.getTime()) {
res = 1;
} else {
res = -1;
}
}
return res;
}
}
public class RSSHandler extends DefaultHandler {
...
List<RSSItem> feed;
RSSItem item;
String mName;
public RssHandler(String name) {
mName = name;
}
List<RSSItem> getFeed() {
return feed;
}
@Override
public void startDocument() throws SAXException {
feed = new ArrayList<>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (localName.equalsIgnoreCase("item")) {
itemFound = true;
item = new RSSItem( name );
currentState = state_unknown;
} else ...
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (localName.equalsIgnoreCase("item")) {
feed.add(item);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
...
case state_pubdate:
SimpleDateFormat formatter = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z"); //make sure you match the format from your XML
item.setPubdate( formatter.parse(stringCharacters) );
break;
...
}
}
}
所有 ... 的意思是让一切保持原样
关于java - 如何合并、创建标签并按升序排列更多 RSS 提要链接的提要,如 Yahoo Pipes 上的提要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35538254/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/