非UI线程修改UI组件

时间:2013-05-07 01:44:52

标签: java android multithreading

我有一个线程需要一直从网络接收数据,我希望这些数据显示给EditText对象。

显然,我无法从接收线程中访问UI EditText;我读到的是我可以使用AsyncTask但是阅读Painless Threading中的示例在我看来,我必须完成接收数据才能将结果发布到UI组件。

我不能使用post或postDelayed,因为两者都将在UI线程上运行,我无法阻止UI接收数据;我需要不断收到数据。

我还有其他选择吗?

4 个答案:

答案 0 :(得分:1)

使用LocalBroadcastManager,包含TextView的Activity将开始侦听广播:

public class MyActivity extends Activity {

    private TextView mTextView;
    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getStringExtra("actionType");
            if(action.equals("updateTextView")){
                mTextView.setText("whatever you want to set");
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Start listening, you can put it on onResume too
        LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter(MyActivity.class.getSimpleName()));
        mTextView = (TextView) findViewById(R.id.something);
    }
}

因此,每当您的线程收到需要更新屏幕的内容时,请调用:

Intent intent = new Intent(MyActivity.class.getSimpleName());
intent.putExtra("actionType", "updateTextView");

// Once this is called, your broadcast receiver in MyActivity should receive it and start processing
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

还要记得在onDestroy或onPause中取消注册。

*旁注:您需要导入android支持v4库,并且可以使用Intent.putExtra("","")通过意图传递简单的String或对象。和Inteng.getExtra("");

答案 1 :(得分:0)

另一种方法是实现数据监听器接口。

public interface DataListener{
    void onUpdateData(MyData data);
}

包含需要更新的UI组件的活动将实现此接口。它将指定需要对更新的数据做什么。 您可能希望将所有实例保存在应用程序中的某个位置。 我假设您有一个不同的线程来处理网络发送/接收操作。收到数据后,您只需致电:

dataListenerInstance.onUpdateData(data)

然后它将激活您在活动中实现的处理程序。

答案 2 :(得分:0)

在MainActivity中调用AsyncTask,但是使用@Override方法onPostExecute(..)

    public class MainActivity extends ActionBarActivity{
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if(Utils.isNetworkAvailable(this)) {
          DownloadFileFromURL downloader = new DownloadFileFromURL(){
               @Override
               protected void onPostExecute(Integer file_content) {
                                    onCompleteLoad();
                                }
                            };
               downloader.execute(new String[]{file_url, fileName});

               ...

onCompleteLoad(); - 将在MainActivity的UI线程中调用。你甚至不需要实现接口!

Secon方式更适合服务器解决方案,但也可以在客户端上使用它是Callable

public class DoGetSize implements Callable<Integer> {
    private final String file_url;
    private int lenghtOfFile = -1;

    public DoGetSize(String file_url) {
        this.file_url = file_url;
    }

    public Integer call() {
        try {
            URL url = new URL(file_url);
            URLConnection connection = url.openConnection();
            connection.connect();
            lenghtOfFile = connection.getContentLength();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return lenghtOfFile;
    }
}

并称之为:

    FutureTask<Integer> task = new FutureTask(new DoGetSize(file_url));
    ExecutorService es = Executors.newSingleThreadExecutor();
    es.submit (task);
    try {
        Integer result = task.get();
        File file = new File(fileName);
        if(file.length() != result.intValue()) {
          // Do something
           ...
        }

    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }

您可以通过这种方式发送和接收任何对象

完整示例请参阅github:https://github.com/app-z/OffLineShop/blob/master/app/src/main/java/net/appz/offlineshop/offlineshop/MainActivity.java

答案 3 :(得分:-1)

您可以使用简单的委派来完成此操作。

class NonUIThread { 
     private NonUIThreadDelegate delegate; //NonUIThreadDelegate can be an interface or an object that has access to your UI thread like an Activity

     public void setDelegate(NonUIThreadDelegate delegate) {
        this.delegate = delegate;
     }

     private void doSomthing() { 
        //do something and at the end:
        delegate.someMethodThatUpdatesThatComponent();
     } 
 }

class TheUIThread implements NonUIThreadDelegate /*assuming you've decided to make NonUIThreadDelegate an interface*/ { // the "delegator"
    /*
    your code
    */

    private void initiateNonUIThread() {
        NonUIThread nonUIThread;
        /*do whatever needed*/
        nonUIThread.setDelegate(this);
        nonUIThread.start();
    }

    public void someMethodThatUpdatesThatComponent() { //will be called by the non ui thread
        //update the UI
    }   
 }

这里解释得更好(当然使用AsincTask):Simple Delegation Pattern in Android