当 UI 线程上的 Runnable 运行 不是一个选项时,如何延迟生成的线程?
How to delay spawned thread when a Runnable run on UI thread isn't an option?
我在上一个问题中遇到了问题,我不确定我的代码是否存在内存泄漏。一些答案与它在 UI 线程上的 运行 有关,因此阻塞。是的,它 运行 在 UI 线程上并且不会产生新线程..
所以为了解决这个问题,我使用 Thread
而不是 Handler
在 UI 之外生成一个新线程。现在的问题是我无法像在 UI 线程中处理 运行 那样延迟它。
这是我之前的问题,我原来的 UI 线程代码是:,下面是生成新线程的更新代码:
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
.
问题的答案
您可以使用条件直到满足,而不是使用 thread.sleep();
Condition.wait(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return textview != null;
}
});
中的 postDelayed 方法
改变,
Thread t = new Thread(new WeakRunnable(txtview));
t.start();
至:
txtview.postDelayed(new WeakRunnable(txtview), 1500);
然后删除您的可运行程序中的以下睡眠子句,因为不再需要它
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
正如@Axxiss 所说,这种情况更适合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) 线程中执行它,没有任何多余的装饰。
我在上一个问题中遇到了问题,我不确定我的代码是否存在内存泄漏。一些答案与它在 UI 线程上的 运行 有关,因此阻塞。是的,它 运行 在 UI 线程上并且不会产生新线程..
所以为了解决这个问题,我使用 Thread
而不是 Handler
在 UI 之外生成一个新线程。现在的问题是我无法像在 UI 线程中处理 运行 那样延迟它。
这是我之前的问题,我原来的 UI 线程代码是:
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
.
您可以使用条件直到满足,而不是使用 thread.sleep();
Condition.wait(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return textview != null;
}
});
改变,
Thread t = new Thread(new WeakRunnable(txtview));
t.start();
至:
txtview.postDelayed(new WeakRunnable(txtview), 1500);
然后删除您的可运行程序中的以下睡眠子句,因为不再需要它
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
正如@Axxiss 所说,这种情况更适合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) 线程中执行它,没有任何多余的装饰。