简体   繁体   English

停止Twitter流并使用twitter4j返回状态列表

[英]stop the Twitter stream and return List of status with twitter4j

Using the code example provided by Twitter4j, I'd like t stop the stream after a list of 1,000 status have been collected, and return this list. 使用Twitter4j提供的代码示例,我想在收集到1,000个状态列表后停止流,并返回此列表。 How can I do that? 我怎样才能做到这一点?

public class Stream {
    public List<Status> execute throws TwitterException {

    List<Status> statuses = new ArrayList();

    ConfigurationBuilder cb = new ConfigurationBuilder();
    cb.setDebugEnabled(true);
    cb.setOAuthConsumerKey("bbb");
    cb.setOAuthConsumerSecret("bbb");
    cb.setOAuthAccessToken("bbb");
    cb.setOAuthAccessTokenSecret("bbb");

    TwitterStream twitterStream = new TwitterStreamFactory(cb.build()).getInstance();

    StatusListener listener = new StatusListener() {

        public void onStatus(Status status) {
            statuses.add(status);
            if (statuses.size>1000){
              //return statuses. Obviously that's not the correct place for a return statement...
            }
        }

        public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
            System.out.println("Got a status deletion notice id:" + statusDeletionNotice.getStatusId());
        }

        public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
            System.out.println("Got track limitation notice:" + numberOfLimitedStatuses);
        }

        public void onScrubGeo(long userId, long upToStatusId) {
            System.out.println("Got scrub_geo event userId:" + userId + " upToStatusId:" + upToStatusId);
        }

        public void onException(Exception ex) {
            ex.printStackTrace();
        }
    };

    FilterQuery fq = new FilterQuery();
    String keywords[] = {"Keyword 1", "Keyword 2"};

    fq.track(keywords);

    twitterStream.addListener(listener);
    twitterStream.filter(fq);

}

Consider using a BlockingQueue as an intermediary, using the listener to add the Status objects to it. 考虑使用BlockingQueue作为中介,使用侦听器向其添加Status对象。

Once the stream has started you can start taking Status es from the queue until you have the one thousand you need. 流启动后,您可以开始从队列中获取Status es,直到您拥有所需的1000个。

As a starting point, it would look something like the following: 作为一个起点,它看起来像下面这样:

public class Stream {
    private static final int TOTAL_TWEETS = 1000;

    public List<Status> execute() throws TwitterException {
        // skipped for brevity...

        // TODO: You may have to tweak the capacity of the queue, depends on the filter query
        final BlockingQueue<Status> statuses = new LinkedBlockingQueue<Status>(10000); 
        final StatusListener listener = new StatusListener() {

            public void onStatus(Status status) {
                statuses.offer(status); // Add received status to the queue
            }

            // etc...
        };

        final FilterQuery fq = new FilterQuery();
        final String keywords[] = {"Keyword 1", "Keyword 2"};
        fq.track(keywords);

        twitterStream.addListener(listener);
        twitterStream.filter(fq);

        // Collect the 1000 statues
        final List<Status> collected = new ArrayList<Status>(TOTAL_TWEETS);
        while (collected.size() < TOTAL_TWEETS) {
            // TODO: Handle InterruptedException
            final Status status = statuses.poll(10, TimeUnit.SECONDS); 

            if (status == null) {
                // TODO: Consider hitting this too often could indicate no further Tweets
                continue;
            }
            collected.add(status);
        }
        twitterStream.shutdown();

        return collected;
    }
} 

It is not a good idea to force an asynchronous piece of code into synchronous mode. 强制异步代码进入同步模式并不是一个好主意。 Please see https://stackoverflow.com/a/5934656/276263 See if you can rework your logic. 请参阅https://stackoverflow.com/a/5934656/276263看看您是否可以重新设计逻辑。

However, the below code works as per your requirement. 但是,以下代码可根据您的要求运行。

public class Stream {

  public static void main(String[] args) throws TwitterException {
    Stream stream = new Stream();
    stream.execute();
  }

  private final Object lock = new Object();
  public List<Status> execute() throws TwitterException {

    final List<Status> statuses = new ArrayList();

    ConfigurationBuilder cb = new ConfigurationBuilder();
    cb.setDebugEnabled(true);
    cb.setOAuthConsumerKey("bbb");
    cb.setOAuthConsumerSecret("bbb");
    cb.setOAuthAccessToken("bbb");
    cb.setOAuthAccessTokenSecret("bbb");

    TwitterStream twitterStream = new TwitterStreamFactory(cb.build())
        .getInstance();

    StatusListener listener = new StatusListener() {

      public void onStatus(Status status) {
        statuses.add(status);
        System.out.println(statuses.size() + ":" + status.getText());
        if (statuses.size() > 100) {
          synchronized (lock) {
            lock.notify();
          }
          System.out.println("unlocked");
        }
      }

      public void onDeletionNotice(
          StatusDeletionNotice statusDeletionNotice) {
        System.out.println("Got a status deletion notice id:"
            + statusDeletionNotice.getStatusId());
      }

      public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
        System.out.println("Got track limitation notice:"
            + numberOfLimitedStatuses);
      }

      public void onScrubGeo(long userId, long upToStatusId) {
        System.out.println("Got scrub_geo event userId:" + userId
            + " upToStatusId:" + upToStatusId);
      }

      public void onException(Exception ex) {
        ex.printStackTrace();
      }

      @Override
      public void onStallWarning(StallWarning sw) {
        System.out.println(sw.getMessage());

      }
    };

    FilterQuery fq = new FilterQuery();
    String keywords[] = { "federer", "nadal", "#Salute" };

    fq.track(keywords);


    twitterStream.addListener(listener);
    twitterStream.filter(fq);

    try {
      synchronized (lock) {
        lock.wait();
      }
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    System.out.println("returning statuses");
    twitterStream.shutdown();
    return statuses;
  }
}

There are two ways: 有两种方法:

If you just need to finish the thread that consumes the stream (this is the thread that calls your listener) you can use twitterStream.cleanUp(); 如果您只需要完成使用流的线程(这是调用您的侦听器的线程),您可以使用twitterStream.cleanUp(); . This will gracefully stop the thread. 这将优雅地停止线程。 You might want to use a boolean stopped variable in your status listener so to ignore any calls that you will receive after this event. 您可能希望在状态侦听器中使用boolean stopped变量,以便忽略在此事件之后将收到的任何调用。

You can also close the stream consuming thread along with its dispatcher thread (that is a deamon thread) by calling twitterStream.shutdown(); 您还可以通过调用twitterStream.shutdown();来关闭流消耗线程及其调度程序线程(即deamon线程twitterStream.shutdown(); However this is a more brutal approach of ending communication with the twitter API. 然而,这是一种结束与twitter API通信的更残酷的方法。 Though it works if you call this from inside the listener, I would prefer the approach suggested by @krishnakumarp 虽然如果你从监听器内部调用它,它可以工作,我更喜欢@krishnakumarp建议的方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM