-1

I have a simple android application which has a menu on its action bar. When the item is selected I call a function startStreaming(). Inside that function I set twitter status listener, so whenever a new tweet comes, I change the graphical interface. Well the program works somehow, but I get some warning like:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

And that's because I am changing the gui in the wrong thread. I tried using AsyncTask where all job was done in onPostExecute but I get again the same warning.

Since I would need some delay, meaning that I will change gui each 3 seconds, I thought I could use a separate Thread and its method runOnUiThread so I could use Thread.sleep(3000). That could also fix my warning.

I would like to get some help to place and modify the content of startStreaming() in a thread.

public class SearchTwitter extends Activity {
    private List<ExampleViewModel> viewModels;
    private ExampleViewModel myRow;
    private ExampleAdapter adapter;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.stream_tag:
                startStreaming();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }   
    }

    private void startStreaming(){
        TwitterStream twitterstream = new TwitterStreamFactory().getInstance();

        twitter4j.StatusListener listener = new twitter4j.StatusListener() {
            @Override
            public void onStatus(twitter4j.Status status) { //new posts arrives 

                if(viewModels.size() > 1){
                    adapter.viewmodels().remove(viewModels.size() - 1);

                    String tweetText = status.getText();
                    myRow = new ExampleViewModel(tweetText);
                    viewModels.add(myRow);

                    adapter.notifyDataSetChanged(); // update UI 
                }
              }
        };

        FilterQuery filterQuery = new FilterQuery();
        String[] query = {"#WorldCup2014"};
        filterQuery.track(query);

        twitterstream.addListener(listener);
        twitterstream.filter(filterQuery); 
      }
  } 
user3764893
  • 697
  • 5
  • 16
  • 33

3 Answers3

1

To change UI in case that no one View assigned to variable you can use

    (findViewById(android.R.id.content)).postDelayed(new Runnable() {
        @Override
        public void run() {
           //Put your change UI logic here
        }
    }, 3000);

(findViewById(android.R.id.content)) is a root View for each activity what you used.

About periodical event you might be read at Best way to periodically executing AsyncTasks in Android

Community
  • 1
  • 1
Sergey Shustikov
  • 15,377
  • 12
  • 67
  • 119
1

Just use a Runnable and runOnUIThread.

runOnUiThread(new Runnable(){

    public void run() {
       //do something
    }

});

This will allow you to update the UI from the main thread from within the onStatus callback and should fix your issue.

I wouldn't even worry about the 3 second delay. Sounds to me like this tweet listener just updates when a new tweet comes in. In that case, why even bother with a delay? Just update each time something calls onStatus.

Rarw
  • 7,645
  • 3
  • 28
  • 46
  • What about the listener, should I set it inside `run` method? – user3764893 Jul 08 '14 at 15:52
  • No - the run method is what you want to run on the UI thread. That's just the part where you update the ListView. You would add this within the listener callback and then place the part where you notify the adapter of the change within run. – Rarw Jul 08 '14 at 16:10
  • I see. But what about that listener, where should I place it? – user3764893 Jul 08 '14 at 16:13
  • Im sorry I don't understand. Is the listener not working correctly? What is wrong with it. – Rarw Jul 08 '14 at 16:34
  • yeah it is working. I did as you suggested but I got some errors `can't create handler inside thread that has not called looper.prepare()` – user3764893 Jul 08 '14 at 16:41
  • Have a look at this post http://stackoverflow.com/questions/11140285/how-to-use-runonuithread something like this should work for you. If you still cannot get it to work let me know. – Rarw Jul 08 '14 at 16:44
0

You don't usually call listeners on their own threads. They are called on the thread that you register the listener on.

Ralph
  • 2,959
  • 9
  • 26
  • 49