Android не может выполнить поток пользователя setListAdapter () - PullRequest
1 голос
/ 29 мая 2010

Извините, мой последний вопрос был плохо отформатирован. Поэтому я удаляю контент и переформулирую вопрос.

Мне понравился ответ @ChrisBunney на мой вопрос с примером обработки изображения в другой теме.

Вот правильный код ниже

public class TestActivity extends ListActivity {

    int count =0;

    List<String> listString = null;

    String[] mString = null; 

      private RefreshHandler mRedrawHandler = new RefreshHandler();

      class RefreshHandler extends Handler {

            @Override

            public void handleMessage(Message msg) {

                TestActivity.this.updateUI();

            }



            public void sleep(long delayMillis) {

              this.removeMessages(0);

              sendMessageDelayed(obtainMessage(0), delayMillis);

            }

          };



          private void updateUI(){



              mRedrawHandler.sleep(1000);

              listString.add("Test "+count++);

              String[] mString = new String[listString.size()];

              int i = 0;

              for(String string : listString){
                  mString[i++]= string;
              }

              if(null != mString && mString.length>0)
              setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mString ));


          }



          @Override 

          public void onCreate(Bundle icicle) { 

            super.onCreate(icicle); 

            setContentView(R.layout.main);

            listString = new LinkedList<String>();


            updateUI();


          } 



}

Я собираюсь вызвать обновление интерфейса пользователя из другого потока.

Это будет модификация моего файла кода выше.

private class HelperClass implements Runnable{

            public void run() {

                performSomeCalculation();

            }

            /*
             * This code will populate the list as it is executed.
             * As and when there is a new element in the list the UI is updated.
             */

            public void performSomeCalculation(){

                //update list String
                updateUI();
            }

/*




/*
           * 
           * The new update onCreate method calling another thread that populates the UI thread
           * 
           */

          @Override 

          public void onCreate(Bundle icicle) { 

            super.onCreate(icicle); 

            setContentView(R.layout.main);

            listString = new LinkedList<String>();


            //updateUI();

            Thread thread = new Thread(new HelperClass());
            thread.start();


          }

Вы можете видеть в приведенном выше коде, что я создал HelperClass для выполнения некоторых вычислений, так как и когда есть выход из потока вычислений, он должен обновить поток пользовательского интерфейса.

Я работаю над этим, чтобы он заработал, если кто-нибудь выяснит, пожалуйста, обновите мой пост.

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 01 июня 2010

Наконец-то с помощью кода Криса получилось решение моего собственного вопроса.

Пожалуйста, обратитесь к коду Криса для описания метода.

Плз поправьте меня за любые условные потери.

Содержимое файла макета выглядит следующим образом.

<ListView 
    android:id="@+id/list"         
    android:layout_span="1" 
    android:layout_width="324px" 
    android:layout_height="348px"/>

Содержимое файла Java выглядит следующим образом.

import java.util.LinkedList;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ArrayAdapter;
import android.widget.ListView;


public class TestApp extends Activity {


    private final Handler handler = new Handler();

    private final UILoadingHelperClass uiLoadingThread = new UILoadingHelperClass();


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        uiLoadingThread.setListView(R.id.list);

        new DataLoadingThread(handler, uiLoadingThread);        


    }


    private class DataLoadingThread extends Thread {

        int count = 0;

        LinkedList<String> linkedList = null;

        private final Handler handler;

        private final UILoadingHelperClass uiLoadingThread;


        public DataLoadingThread(Handler handler, UILoadingHelperClass uiLoadingThread) {
            this.handler = handler;
            this.uiLoadingThread = uiLoadingThread;
            this.start();
        }

        @Override
        public void run() {

            while(true){
                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                if(null == linkedList)
                    linkedList = new LinkedList<String>();

                linkedList.add("Test "+count++);

                int i=0;

                String[] strings = new String[linkedList.size()];

                for(String string : linkedList)
                    strings[i++]=string;

                uiLoadingThread.setSttrings(strings);

                handler.post(uiLoadingThread);
            }

        }
    }


    private class UILoadingHelperClass implements Runnable {

        private ListView listView = null;

        private String[] strings = null;

        public void setSttrings(String[] strings){
            this.strings = strings;
        }

        public void setListView(int id){
            listView = (ListView)findViewById(id);
        }

        public void run() {
            if(null != strings && strings.length>0)
                listView.setAdapter(new ArrayAdapter<String>(TestApp.this,android.R.layout.simple_list_item_1,strings));        

        }      
    }
}
0 голосов
/ 29 мая 2010

Если вы хотите выполнять операции блокировки потоков, которые обновляют пользовательский интерфейс (например, загрузка изображения из Интернета), вы должны использовать класс Handler для создания обратного вызова.

http://developer.android.com/reference/android/os/Handler.html

Класс Handler будет привязан к потоку пользовательского интерфейса и позволит вам размещать объекты, реализующие интерфейс Runnable, в очередь для выполнения в правильном потоке.

Однако я не уверен, возможно ли достичь того, к чему вы, похоже, стремитесь, из данного кода. Некоторая дополнительная информация об обстоятельствах и желаемом поведении будет полезна.

Типичная реализация, использующая Handler для обновления пользовательского интерфейса, основанная на коде из моего собственного приложения, которое загружает статическую карту и обновляет пользовательский интерфейс, может выглядеть следующим образом:

public class HandlerExample extends Activity {


/**
 * Handler to allow other threads to send executable messages (in the form
 * of Runnable objects) to the main UI thread. This is used to download the
 * static image in a separate thread to stop the UI from blocking
 */
private final Handler handler = new Handler();
/**
 * Runnable implementation that, in conjunction with handler, displays a
 * given static map in the ImageView
 */
private final UpdateStaticMap updateStaticMap = new UpdateStaticMap();


@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

        //... other initialisation

    // This object implements Runnable and is used to post our update to the Handler
    updateStaticMap.setImageView((ImageView)findViewById(R.id.venuedetail_mapimage));
    // Then we pass the Runnable object, the Handler, and all the data we
    // need to get the
    // map into a Thread subclass to avoid blocking the UI thread
            // Note, the thread is started in the constructor so we don't worry about it here
    new MapGetter(handler, updateStaticMap);


}

/**
 * This private class extends Thread to handle the downloading of the static
 * map separately from the main UI thread to avoid
 * blocking it. It uses the Handler to trigger the UI thread to update the
 * ImageView when it's finished by passing updateStaticMap as a message
 * (it's a Runnable, thus will be executed by the handler in the UI thread).
 * This is necessary as only the thread that created the View components can
 * edit them.
 * 
 * @author Chris Bunney
 * 
 */
private class MapGetter extends Thread {

    /**
     * The Handler associated with the UI thread. Used to pass the map back
     * to the UI thread
     */
    private final Handler handler;
    /**
     * The Runnable implementation used to wrap the bitmap when passing it
     * back to the UI thread via handler
     */
    private final UpdateStaticMap updateStaticMap;

    /**
     * 
     * 
     * @param handler
     *            Handler for the UI thread so the MapGetter can update the
     *            ImageView with the map
     * @param updateStaticMap
     *            Runnable object that is used to send the map back to and
     *            update the UI
     **/
    public MapGetter(Handler handler, UpdateStaticMap updateStaticMap) {
        this.handler = handler;
        this.updateStaticMap = updateStaticMap;
        this.start();
    }

    /**
     * Obtains the Static Map and passes it back to the main
     * UI thread to be displayed
     */
    @Override
    public void run() {
                    //Note, the getImage() method is just a stand in for whatever code you need to get the image
        updateStaticMap.setBitmap(getImage()));
                    //Now our Runnable object has all the data it needs, we post it back to the Handler
        handler.post(updateStaticMap);

    }
}

/**
 * This class implements the Runnable interface. It acts a message to be
 * delivered to the UI thread. This class updates a given ImageView with a
 * given Bitmap. The ImageView and Bitmap form the payload of the message.
 * This class is necessary because only the thread that created a View can
 * alter it, so the object is passed to the correct thread and executed by
 * it.
 * 
 * @author Chris Bunney
 * 
 */
private class UpdateStaticMap implements Runnable {

    /**
     * The ImageView to target when setting the bitmap
     */
    private ImageView mapImage;
    /**
     * The Bitmap to update the ImageView with
     */
    private Bitmap bm;

    /**
     * Inserts the Bitmap, bm, into the ImageView, mapImage
     * 
     */
    @Override
    public void run() {
        mapImage.setImageBitmap(bm);
        Log.d(TAG, "run: Static Map Updated");
    }

    /**
     * Accessor method to insert the bitmap payload into the message
     * 
     * @param bm
     *            Static map to be displayed in the UI
     */
    public void setBitmap(Bitmap bm) {
        this.bm = bm;
        Log.d(TAG, "setBitmap: Bitmap updated");
    }

    /**
     * Accessor method to associate the object with a particular ImageView
     * 
     * @param mapImage
     *            ImageView that the map should be displayed in
     */
    public void setImageView(ImageView mapImage) {
        this.mapImage = mapImage;
        Log.d(TAG, "setImageView: ImageView updated");
    }
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...