2

I am a newbie in Android and creating a mini FTP download manager for myself.. I am using multithreading, each thread to handle one download or upload. In the MainActivity.java, I am using two spinners in the view. One to list the files on the server (which can be downloaded), another to list files on my phone folder (which can be uploaded). I want to update the first (download) spinner when a new file is uploaded, and the second (upload) spinner when a new file is downloaded. However I am not able to make out how to update the spinners only when the corresponding threads finish their job. I created methods to update the spinners in the MainActivity.java and tried to call them in the end of the run() of the threads, so that they'l be updated once the threads finish downloading/uploading. However, I am getting an error in LogCat saying

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

The method for updating upload spinner is:

void upScrollUpdate() {
    spinup=(Spinner)findViewById(R.id.uploadspin);
    spinup.setEnabled(false);
    String[] upload={"No Files"};
    File sdDir=Environment.getExternalStorageDirectory();
    File dir=new File (sdDir.getAbsolutePath() + "/aFTP");
    File[] fArray=dir.listFiles();
    if(fArray.length>0) {
        upload=new String[fArray.length];
    }
    for(int i=0;i<fArray.length;i++) {
        upload[i]=fArray[i].getName();
    }
    ArrayAdapter<String> saaUpload=new ArrayAdapter<String>(this,android.R.layout.simple_spinner_dropdown_item,upload);
    spinup.setAdapter(saaUpload);
    if(spinup.getSelectedItem().toString().equalsIgnoreCase("No Files")) {
        uploadButton.setEnabled(false);
    }
    spinup.setEnabled(true);
}

Why cant this method be called from another thread, and what is the other way out of this, I simply want to update the spinners but I have spent a whole day on this only thing...

arjoan
  • 1,849
  • 2
  • 20
  • 39
upInCloud
  • 979
  • 2
  • 10
  • 29

2 Answers2

2

For any piece of code that will update the UI, put that in this block:

Refer to this link for more info on runOnUiThread

runOnUiThread(new Runnable() {
     public void run() {

         // RUN THE CODE WHICH IS GIVING THAT EXCEPTION HERE

    }
});

The same can also be done like this:

Runnable run = new Runnable() {

    @Override
    public void run() {

        // RUN THE CODE WHICH IS GIVING THAT EXCEPTION HERE

    }
}; YourActivity.this.runOnUiThread(run);

Alternatively, you can make use of an AsyncTask. You can do your processing in the doInBackground() method and then update the Spinners in the onPostExecute() method of the AsyncTask

EDIT: Check these tutorials to help you get started with using AsyncTask:

  1. http://www.vogella.com/articles/AndroidPerformance/article.html#asynctask
  2. http://androidresearch.wordpress.com/2012/03/17/understanding-asynctask-once-and-forever/
  3. http://android10.org/index.php/articlesother/239-android-application-and-asynctask-basics
  4. http://mobileorchard.com/android-app-developmentthreading-part-2-async-tasks/
  5. http://thenewboston.org/watch.php?cat=6&number=101

The 5th link to thenewboston.org has about 200 odd video tutorials on YouTube here: http://www.youtube.com/course?list=EC2F07DBCDCC01493A&feature=plcp

EDIT 2: Check the edit in this link here: https://stackoverflow.com/a/13265776/450534

It is at the bottom of the answer.

Community
  • 1
  • 1
Siddharth Lele
  • 27,623
  • 15
  • 98
  • 151
  • Ohhh....I was creating new class that implements Runnable and has a Thread object... and I was passing that class constructor in the runOnUiThread(), It was still giving the same error...doing like you showed above works fine! Thanks a lot! – upInCloud Nov 24 '12 at 06:34
  • @ShaaradDalvi: Glad to have helped. :-) – Siddharth Lele Nov 24 '12 at 06:36
  • However, When I call MainActivity.this.runOnUiThread(//mycode); from inside the onClick of Download button, The MainActivity freezes, which defeats the purpose of multithreading I wanted... the button remains pushed until the download completes, and I cant click on any other component too. The spinner gets updated correctly after download and only then the app resumes working.. – upInCloud Nov 24 '12 at 06:46
  • @ShaaradDalvi: I would recommend using an AsyncTask to do the processing without causing these UI hiccups. Give me a minute or two to grab a few tutorials to help you get started. I will edit the post with the links. – Siddharth Lele Nov 24 '12 at 06:47
  • :-) Thanks a lot! I will also see the tutorials on AsyncTask and how it works..maybe that is the solution I want.. – upInCloud Nov 24 '12 at 06:53
  • Thank you very much! I am trying to implement AsyncTask now...I think onPostExecute() will help the lags in the UI till the download completes! – upInCloud Nov 24 '12 at 07:02
  • @ShaaradDalvi: I would also suggest showing a ProgressBar while you are processing information. Let me get a quick example from an answer I had posted earlier. – Siddharth Lele Nov 24 '12 at 07:05
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/20028/discussion-between-shaarad-dalvi-and-siddharth-lele) – upInCloud Nov 24 '12 at 07:15
1

Anything to do with views should be done on UI thread. You can use activityInstance.runOnUIThread() to handle this scenario of updating views from different thread.

Refer: Android: RunOnUiThread vs AsyncTask

Community
  • 1
  • 1
arjoan
  • 1,849
  • 2
  • 20
  • 39