Как задержать порожденный поток, когда 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) без излишеств.

Другие вопросы по тегам