how to make toast from another thread (sans runOnUiThread)
I need to make an Android toast from a processing thread, which is custom for OpenCV so I can't use runOnUiThread() as suggested here: Android: Toast in a thread.
Most of this code is from the CVCamera sample app. But those unfamiliar, when I select the Surf menu button, the SURFProcessor is called like so:
else if (item.getTitle().equals("SURF")) {
defaultcallbackstack.addFirst(new SURFProcessor());
toasts(DIALOG_TUTORIAL_SURF, "");
}
This Processor thread is run so that when I press the phone's camera button (capturePress = true), an image is taken and processing done. I want to call toasts method as shown:
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);
capturePre开发者_开发问答ss = false;
toasts(PROCESS_MESSAGE, processMsg);
}
}
}
Here is the toasts method, located in the main class extending Activity:
void toasts(int id, String msg) {
switch (id) {
case PROCESS_MESSAGE:
Toast.makeText(MMRapp.this, msg, Toast.LENGTH_LONG).show();
break;
.........
Right now this code gives me an error: "can't create handler inside thread that has not called Looper.prepare()." How do I go about calling the toasts method? Or is it possible to have the toasts method listen for a change in processMsg? If possible, I can get by with sending the processMsg or changing a class variable instead. In essence, I need a String updated from this Processor thread.
Thank you very much, and I will provide more info/code if wanted.
-Tomuse a handler and a runnable Make the Handler and runnable in the activity:
// these are members in the Activity class
Handler toastHandler = new Handler();
Runnable toastRunnable = new Runnable() {public void run() {Toast.makeText(Activity.this,...).show();}}
then to invoke it from your thread use
toastHandler.post(toastRunnable);
The handler executes the runnable in the thread it was created in.
Use the overload that fit your needs.
/**
* 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);
}
}
Why not simply to use a broadcast reveiver?
Write it
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();
}
}
}
Define it
<receiver
android:name=".receivers.ToastTrigger"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.example.TOAST" />
</intent-filter>
</receiver>
Trigger it
public void showMessage(String message) {
Intent intent = new Intent();
intent.setAction(getPackageName() + ".TOAST");
intent.putExtra(ToastTrigger.EXTRA_MESSAGE, message);
sendBroadcast(intent);
}
精彩评论