2011-03-22 14 views
5

Necesito hacer un pan tostado de Android a partir de un hilo de procesamiento, que es personalizado para OpenCV, así que no puedo usar runOnUiThread() como se sugiere aquí: Android: Toast in a thread.cómo hacer tostadas desde otro hilo (sans runOnUiThread)

La mayor parte de este código es de la aplicación de muestra CVCamera. Pero los que no conocen, cuando selecciono el botón de menú de la resaca, el SURFProcessor se llama así:

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

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

      } 

Este hilo procesador se ejecuta de manera que cuando se presiona el botón de la cámara del teléfono (capturePress = true), se toma una imagen y procesamiento hecho. Quiero llamar al método tostadas como se muestra:

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); 
        } 
      } 
} 

Aquí es el método tostadas, que se encuentra en la clase principal que se extiende Actividad:

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

En este momento este código me da un error: "no se puede crear controlador en el hilo que no ha llamado a Looper.prepare(). " ¿Cómo hago para llamar al método de las tostadas? ¿O es posible hacer que el método de las tostadas escuche un cambio en processMsg? Si es posible, me las puedo arreglar enviando el processMsg o cambiando una variable de clase. En esencia, necesito una cadena actualizada a partir de este hilo del procesador.

Muchas gracias, y le proporcionaré más información/código si lo desea.
-Tom

Respuesta

6

uso de un controlador y un ejecutable Hacer el Handler y ejecutable en la actividad:

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

luego invocarlo del uso de hilo

toastHandler.post(toastRunnable); 

El controlador ejecuta la ejecutable en el hilo en el que se creó.

+0

gracias! funciona como un encanto ... pensé que tenía que haber una manera simple de hacerlo. – wrapperapps

1

Use la sobrecarga que se ajuste a sus necesidades.

/** 
* 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); 
    } 
} 
+0

Para el beneficio de otros que están leyendo esta pregunta y su respuesta, ¿podría ser más específico acerca de cómo esto resuelve el problema? ¿Cuál de estos debe usarse para el caso que solicitó el póster original? –

+1

Bueno, es bastante simple. El problema de OP es que está intentando publicar brindis fuera del hilo de la interfaz de usuario y eso no está permitido. Mi fragmento se ocupa de eso. Dependiendo de qué objeto tiene acceso en su código (un contexto BroadcastReceiver, una actividad, una aplicación, etc.) puede usar una sobrecarga u otra. Tal vez este: 'public static void showToast (Contexto final mContext, final CharSequence sMessage)' – Reaper

+0

Esta elaboración es muy útil. ¡Gracias por ampliar esto! –

0

¿Por qué no simplemente utilizar un emisor de difusión?
escritura que

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(); 
     } 
    } 
} 

definirlo

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

desencadenarla

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