我有一個線程需要從網絡中隨時接收數據,我希望將這些數據顯示給EditText對象。非UI線程修改UI組件
顯然,我無法從我的接收線程中訪問UI EditText;我讀到的是,我可以使用AsyncTask,但是閱讀Painless Threading中的示例,在我看來,我必須先完成接收數據,然後才能將結果發佈到UI組件。
我無法使用post或postDelayed,因爲兩者都將在UI線程上運行,而且我無法阻止UI接收數據;我需要不斷收到數據。
我還有其他選擇嗎?
我有一個線程需要從網絡中隨時接收數據,我希望將這些數據顯示給EditText對象。非UI線程修改UI組件
顯然,我無法從我的接收線程中訪問UI EditText;我讀到的是,我可以使用AsyncTask,但是閱讀Painless Threading中的示例,在我看來,我必須先完成接收數據,然後才能將結果發佈到UI組件。
我無法使用post或postDelayed,因爲兩者都將在UI線程上運行,而且我無法阻止UI接收數據;我需要不斷收到數據。
我還有其他選擇嗎?
使用LocalBroadcastManager,你含TextView的開始收聽廣播的活動:
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(「」,「」)和Inteng.getExtra(「」);通過意圖傳遞簡單的String或對象。
你可以使用簡單的委託來做到這一點。
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
另一種方式是實現數據監聽器接口。
public interface DataListener{
void onUpdateData(MyData data);
}
包含需要更新的UI組件的活動將實現此接口。它將指定更新數據需要做什麼。 您可能想要將這些數據偵聽器界面的所有實例保存在您的應用程序的某處。 我假設你有一個不同的線程來處理網絡發送/接收操作。在接收數據時,您只需撥打:
dataListenerInstance.onUpdateData(data)
然後它會激活您在活動中實施的處理程序。
在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線程中調用。你甚至不需要實現Interface!
塞康方式更適合的服務器解決方案,但也可以在客戶端上使用的是可贖回
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
我知道我的問題我這很愚蠢,但我怎樣才能訪問onReceive方法中的我的UI組件? – Fingolfin 2013-05-07 02:39:50
嗯,沒有問題是愚蠢的。通常你會在MyActivity類中聲明一些類變量。我將編輯第一部分代碼。 – 2013-05-07 02:42:19
它的工作原理:)請讓我試着瞭解這裏發生了什麼: 我們基本上將我們從一個線程接收到的數據廣播到整個過程,因此在此過程中的任何廣播偵聽器都會使用intent捕獲它;對? – Fingolfin 2013-05-07 03:02:32