主 Activity 完成后如何从服务中显示 Toast?
Posted
技术标签:
【中文标题】主 Activity 完成后如何从服务中显示 Toast?【英文标题】:How to display Toast from a Service after main Activity finishes? 【发布时间】:2015-02-06 02:48:11 【问题描述】:更新:我不同意这是重复的 - 因为我正在寻找一种方法来退出主应用程序并仍然显示服务中的 Toast。
在 a very simple test app 我有 2 个按钮:
单击任何按钮将运行带有相应操作字符串(“open”或“flash”)的服务-
OpenActivity.java:
public class OpenActivity extends Activity
private Intent mServiceIntent;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_open);
mServiceIntent = new Intent(this, RegionService.class);
public void openCar(View v)
mServiceIntent.setAction("open");
startService(mServiceIntent);
RegionService.java:
public class RegionService extends IntentService
private static final String TAG = "RegionService";
@Override
protected void onHandleIntent(Intent intent)
Log.d(TAG, "Received an intent: " + intent);
String action = intent.getAction();
Log.d(TAG, "Received an action: " + action);
if(action.equals("open"))
Toast.makeText(this,
getString(R.string.car_opened),
Toast.LENGTH_SHORT).show();
不幸的是,我的应用崩溃了:
D/RegionService(24506): Received an intent: Intent act=open cmp=de.afarber.mynotification/.RegionService
D/RegionService(24506): Received an action: open
W/MessageQueue(24506): Handler (android.os.Handler) 422768a8 sending message to a Handler on a dead thread
W/MessageQueue(24506): java.lang.RuntimeException: Handler (android.os.Handler) 422768a8 sending message to a Handler on a dead thread
W/MessageQueue(24506): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:320)
W/MessageQueue(24506): at android.os.Handler.enqueueMessage(Handler.java:626)
W/MessageQueue(24506): at android.os.Handler.sendMessageAtTime(Handler.java:595)
W/MessageQueue(24506): at android.os.Handler.sendMessageDelayed(Handler.java:566)
W/MessageQueue(24506): at android.os.Handler.post(Handler.java:326)
W/MessageQueue(24506): at android.widget.Toast$TN.hide(Toast.java:370)
W/MessageQueue(24506): at android.app.ITransientNotification$Stub.onTransact(ITransientNotification.java:54)
W/MessageQueue(24506): at android.os.Binder.execTransact(Binder.java:412)
W/MessageQueue(24506): at dalvik.system.NativeStart.run(Native Method)
作为一个Android编程新手我想知道如何以正确的方式显示来自Service的Toast?
我想我已经在 Android Home 看到了 Toast(即设备屏幕上没有 Activity,但仍然有 Toast)。
我的背景:我想通过我的服务监控信标设备并显示一些文本 Toast - 即使我的应用已关闭。
【问题讨论】:
jjoe64.com/2011/09/show-toast-notification-from-service.html Toast created in an IntentService never goes away的可能重复 我不同意这是重复的 - 因为在我的情况下,我想退出主应用程序并仍然显示服务中的 Toast。 【参考方案1】:OnHandleIntent
将以不同的Thread
运行
所以你在一个线程中显示Toast
,这在android中是不允许的
所以像这样改变你的代码
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable()
@Override
public void run()
Toast.makeText(getApplicationContext(),
getString(R.string.car_opened),
Toast.LENGTH_SHORT).show();
);
来自dead thread in service
IntentService 将创建一个线程来处理新的意图,并在任务完成后立即终止它。因此,Toast 将不受死线程的控制。
当 toast 显示在屏幕上时,您应该会在控制台中看到一些异常。
【讨论】:
我已尝试将您的代码摘录放入 onHandleIntent - 但它无法编译,因为 this 是Runnable
。
@AlexanderFarber 放置 YourService.this 而不是 this 或更改为 getApplicationContext()
如果有人仍然无法显示 Toast,只需覆盖 onCreate 并在此处初始化 Handler,而不是在 onHandleIntent() 中初始化。仅在 onHandleIntent() 中调用 post 方法。【参考方案2】:
IntentService 有一些限制:
它不能直接与您的用户界面交互。把它的 结果在 UI 中,您必须将它们发送到 Activity。
一切都发生在后台线程而不是 UI 线程,所以你需要一种不同的方式,如下所示:
@Override
public void onCreate()
super.onCreate();
mHandler = new Handler();
@Override
protected void onHandleIntent(Intent intent)
mHandler.post(new Runnable()
@Override
public void run()
Toast.makeText(MyIntentService.this, "Hello Toast!", Toast.LENGTH_LONG).show();
);
来源:Toast created in an IntentService never goes away
【讨论】:
【参考方案3】:OnHandleIntent
在后台线程上调用,任何触摸 UI 的尝试都会导致崩溃。使用 Handler 在 UI 线程上发布 Runnable 以显示您的 toast。
private class MyRunnable implements Runnable
final int mTextId = -1;
final Context mContext;
public MyRunnable(Context c, int textId)
mTextId = textId;
mContext = c;
@Override
public void run()
Toast.makeText(mContext,
getString(mTextId),
Toast.LENGTH_SHORT).show();
Handler handler = new Handler();
handler.post(new MyRunnable(this, R.string.car_opened));
【讨论】:
你为什么不试试所有这些代码sn-ps? :) 当然我尝试了 sn-ps,但有时错误/崩溃不是立即可见的(尤其是当某些东西在后台运行时) - 这就是为什么最好问一下。【参考方案4】:使用以下代码:
runOnUiThread(new Runnable()
public void run()
// UI code goes here
);
【讨论】:
是的,即使服务在后台运行,它也会显示 Activity实例可以传递给服务 是的,一旦你旋转屏幕,你也会泄漏实例。您不需要 Activity 即可访问主线程。 它可以工作,但也可以直接使用服务上下文显示 toast。 您可以使用任何上下文来创建 toast 但是关键是您必须在 UI 线程上调用Toast.show()
才能使其正常工作。【参考方案5】:
这个问题是因为没有从 main_thread 运行 Toast,为了克服这个问题,
创建 Activity 时,从 onCreate()
方法保存它的上下文:
public static Context ctx;
// the method responsible for running the MainActivity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
ctx = this;
然后,在服务中添加一个处理程序并从中运行一个线程(因为处理程序是通过主线程执行的):
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable()
@Override
public void run()
Toast.makeText(OpenActivity.ctx, getString(R.string.car_opened),
Toast.LENGTH_SHORT).show();
);
【讨论】:
为什么需要存储this
?
@LittleChild 因为我不知道他的服务的线程状态并且没有应用程序结构和线程的概述,所以取消保存它大部分会起作用,但在某些情况下不会,所以我保存了它以确保它一定会运行。
您可以在github.com/afarber/android-newbie/tree/q12/MyNotification/src/…查看我的完整应用程序
@AlexanderFarber 没有问题,没有好坏之分,但它可以确保您不会在 serviceintent 上下文中遇到麻烦。
@MuhammedRefaat 你的意思是为了以防万一服务被意外破坏??以上是关于主 Activity 完成后如何从服务中显示 Toast?的主要内容,如果未能解决你的问题,请参考以下文章
Selenium 如何从 iframe 切换回主文档进行操作
在使用存储在 JSON 上的 ID 进行 SearchView 过滤后,如何从 ListView 打开 Activity
无论应用程序状态如何,都可以从通知中正确启动 Activity