как сделать тост из другого потока (без runOnUiThread)

Мне нужно сделать тост Android из потока обработки, который настраивается для OpenCV, поэтому я не могу использовать runOnUiThread (), как предлагается здесь: Android: тост в ветке.

Большая часть этого кода взята из примера приложения CVCamera. Но те, кто незнакомы, когда я выбираю кнопку меню Surf, SURFProcessor вызывается так:

           else if (item.getTitle().equals("SURF")) {

                   defaultcallbackstack.addFirst(new SURFProcessor());
                   toasts(DIALOG_TUTORIAL_SURF, "");

           }

Этот поток процессора запускается так, что, когда я нажимаю кнопку камеры телефона (capturePress = true), снимается изображение и выполняется обработка. Я хочу вызвать метод тостов, как показано:

class SURFProcessor implements NativeProcessor.PoolCallback {

           @Override
           public void process(int idx, image_pool pool, long timestamp,
                           NativeProcessor nativeProcessor) {
                   if(capturePress) {
                           String processMsg = processor.processFeatures(idx, pool, cvcamera.DETECT_SURF);
                           capturePress = false;
                           toasts(PROCESS_MESSAGE, processMsg);
                   }
           }
}

Вот метод тостов, расположенный в основном классе, расширяющем Activity:

void toasts(int id, String msg) {
           switch (id) {
           case PROCESS_MESSAGE:
                   Toast.makeText(MMRapp.this, msg, Toast.LENGTH_LONG).show();
                   break;
.........

Прямо сейчас этот код дает мне ошибку: «не могу создать обработчик внутри потока, который не вызвал Looper.prepare ()». Как мне вызвать метод тостов? Или возможно, чтобы метод тостов отслеживал изменение в processMsg? Если возможно, я могу обойтись отправкой processMsg или изменением переменной класса. По сути, мне нужно обновить строку из этого потока процессора.

Большое спасибо, и я предоставлю дополнительную информацию / код, если хотите.
-Tom


person wrapperapps    schedule 22.03.2011    source источник


Ответы (3)


используйте обработчик и выполняемый. Сделайте обработчик и выполняемый в действии:

// these are members in the Activity class
Handler toastHandler = new Handler();
Runnable toastRunnable = new Runnable() {public void run() {Toast.makeText(Activity.this,...).show();}}

затем, чтобы вызвать его из вашего потока, используйте

toastHandler.post(toastRunnable);

Обработчик выполняет runnable в потоке, в котором он был создан.

person siliconeagle    schedule 22.03.2011
comment
благодарю вас! работает как шарм ... я подумал, что должен быть простой способ сделать это. - person wrapperapps; 22.03.2011

Используйте перегрузку, которая соответствует вашим потребностям.

/**
 * Muestra un toast sin necesidad de preocuparse de estar en el hilo de la
 * UI o no.
 *
 * @param mContext
 * @param sMessage
 */
public static void showToast(final Context mContext, final int nMessageId) {
    if (Utils.isUiThread()) {
        Toast.makeText(mContext.getApplicationContext(), nMessageId, Toast.LENGTH_LONG).show();
        return;
    }
    Runnable mRunnableToast = new Runnable() {
        @Override
        public void run() {
            Toast.makeText(mContext.getApplicationContext(), nMessageId, Toast.LENGTH_LONG).show();
        }
    };
    if (mContext instanceof Activity) {
        ((Activity) mContext).runOnUiThread(mRunnableToast);
        return;
    }
    Utils.runOnUiThread(mRunnableToast);
}

/**
 * Muestra un toast sin necesidad de preocuparse de estar en el hilo de la
 * UI o no.
 *
 * @param mContext
 * @param sMessage
 */
public static void showToast(final Context mContext, final CharSequence sMessage) {
    if (Utils.isUiThread()) {
        Toast.makeText(mContext.getApplicationContext(), sMessage, Toast.LENGTH_LONG).show();
        return;
    }
    Runnable mRunnableToast = new Runnable() {
        @Override
        public void run() {
            Toast.makeText(mContext.getApplicationContext(), sMessage, Toast.LENGTH_LONG).show();
        }
    };
    if (mContext instanceof Activity) {
        ((Activity) mContext).runOnUiThread(mRunnableToast);
        return;
    }
    Utils.runOnUiThread(mRunnableToast);
}

public static boolean isUiThread() {
    Looper mCurrentLooper = Looper.myLooper();
    if (mCurrentLooper == null) {
        return false;
    }
    if (mCurrentLooper.equals(Looper.getMainLooper())) {
        return true;
    }
    return false;
}

public static void runOnUiThread(Runnable mRunnable, Context mContext) {
    if (mContext instanceof Activity) {
        runOnUiThread(mRunnable, (Activity) mContext);
    } else {
        Utils.runOnUiThread(mRunnable);
    }
}

public static void runOnUiThread(Runnable mRunnable, View vView) {
    if (Utils.isUiThread()) {
        mRunnable.run();
    } else {
        vView.post(mRunnable);
    }
}

public static void runOnUiThread(Runnable mRunnable, Activity mActivity) {
    if (mActivity != null) {
        mActivity.runOnUiThread(mRunnable);
    } else {
        Utils.runOnUiThread(mRunnable);
    }
}

public static void runOnUiThread(Runnable mRunnable) {
    if (Utils.isUiThread()) {
        mRunnable.run();
    } else {
        Handler mUiHandler = new Handler(Looper.getMainLooper());
        mUiHandler.post(mRunnable);
    }
}
person Reaper    schedule 06.07.2016
comment
Не могли бы вы уточнить, как это решает проблему, в интересах других, читающих этот вопрос и ваш ответ? Что из этого следует использовать в случае, если исходный плакат был задан? - person Mike Zavarello; 06.07.2016
comment
Что ж, это довольно просто. Проблема OP в том, что он пытается публиковать тосты за пределами потока пользовательского интерфейса, а это запрещено. Мой фрагмент позаботится об этом. В зависимости от того, к какому объекту он имеет доступ в своем коде (контекст BroadcastReceiver, Activity, Application и т. Д.), Он может использовать ту или иную перегрузку. Может быть, этот: public static void showToast(final Context mContext, final CharSequence sMessage) - person Reaper; 07.07.2016
comment
Это уточнение очень полезно. Спасибо за то, что подробно остановились на этом! - person Mike Zavarello; 07.07.2016

Почему бы просто не использовать радиовещание?
Напишите это

public class ToastTrigger extends BroadcastReceiver {

    public static final String EXTRA_MESSAGE = "message";

    @Override
    public void onReceive(Context context, Intent intent) {
        Timber.d("ToastTrigger: received");
        if (intent.hasExtra(EXTRA_MESSAGE)) {
            Toast.makeText(context, intent.getStringExtra(EXTRA_MESSAGE), Toast.LENGTH_SHORT)
                .show();
        }
    }
}

Определите это

    <receiver
        android:name=".receivers.ToastTrigger"
        android:enabled="true"
        android:exported="false">
        <intent-filter>
            <action android:name="com.example.TOAST" />
        </intent-filter>
    </receiver>

Запустить его

public void showMessage(String message) {
    Intent intent = new Intent();
    intent.setAction(getPackageName() + ".TOAST");
    intent.putExtra(ToastTrigger.EXTRA_MESSAGE, message);
    sendBroadcast(intent);
}
person Vlad    schedule 01.01.2018