Как задержать порожденный поток, когда Runnable запустить в потоке пользовательского интерфейса не вариант?
У меня были проблемы с предыдущим вопросом, из-за которого я не был уверен, есть ли в моем коде утечка памяти. Несколько ответов были связаны с тем, что он запускается в потоке пользовательского интерфейса и поэтому блокируется. Это правда, он работает в потоке пользовательского интерфейса и не создает новый..
Так что для ее решения я использую Thread
вместо Handler
создать новый поток за пределами пользовательского интерфейса. Проблема сейчас в том, что мне не удается отложить это, как я сделал с тем, что выполнялось в потоке пользовательского интерфейса.
Это мой предыдущий вопрос, где мой исходный код потока пользовательского интерфейса: безопасен ли этот Runnable от утечки памяти? и следующее - это обновленный код, который порождает новый поток:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private static TextView txtview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
Thread t = new Thread(new WeakRunnable(txtview));
t.start();
}
private static final class WeakRunnable implements Runnable {
private final WeakReference<TextView> mtextview;
protected WeakRunnable(TextView textview){
mtextview = new WeakReference<TextView>(textview);
}
@Override
public void run() {
TextView textview = mtextview.get();
if (textview != null) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
int test = 5*5;
txtview.setText("Hola Mundo"+test);
}
Log.d("com.example.helloworld", "" + Thread.currentThread().getName()); // Outputs "Thread-<num>" if not running on UI thread
}
}
}
Он просто устанавливает вид текста и добавляет результат 5*5
,
Как только я запускаю приложение, оно перестает работать, и я не понимаю, почему. Что-то говорит мне, что я задерживаю это неправильно или использую runOnUiThread
неправильно. Даже меняется txtview.setText("Hola Mundo"+test);
в runOnUiThread( txtview.setText("Hola Mundo"+test) );
не компилируется с ошибкой: 'void' type not allowed here
,
В двух словах: вычисление (5*5
в этом случае) должен выполняться в отдельном потоке, чтобы избежать блокировки основного потока (UI), а текст должен быть установлен в UI, принимая вычисляемый элемент из отдельного потока. Ваш собственный простой пример тоже подойдет.
ОБНОВЛЕНИЕ Я разместил ответ на свой вопрос реализации AsyncTask
,
3 ответа
Вы можете использовать условие, пока оно не будет выполнено, вместо использования thread.sleep();
Condition.wait(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return textview != null;
}
});
Используйте метод postDelayed, найденный в классе Handler и Views
менять,
Thread t = new Thread(new WeakRunnable(txtview));
t.start();
к:
txtview.postDelayed(new WeakRunnable(txtview), 1500);
Затем удалите следующее условие сна в вашем runnable, так как оно больше не нужно
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Как сказал @Axiss, этот случай лучше подходит для AsyncTask
, Я обновил свой код для использования AsyncTask
с WeakReference
чтобы избежать утечек памяти:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.AsyncTask;
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private static TextView txtview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
SimpleTask objSimpleTask=new SimpleTask();
objSimpleTask.execute();
}
private static class SimpleTask extends AsyncTask<Void,Void,String> {
private WeakReference<TextView> mtextview = new WeakReference<TextView>(txtview);
@Override
protected String doInBackground(Void... params) {
Log.d("com.example.helloworld", "" + Thread.currentThread().getName());
try{
Thread.sleep(1500);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
return "Hola Mundo";
}
@Override
protected void onPostExecute(String result) {
TextView mtxtview = mtextview.get();
mtxtview.setText(result);
}
}
}
doInBackground
выполняет код в отдельном потоке, в то время как вы можете позже поймать результат с onPostExecute
и выполнить его в основном потоке (UI) без излишеств.