从服务内部显示 Snackbar

Posted

技术标签:

【中文标题】从服务内部显示 Snackbar【英文标题】:Showing a Snackbar from inside a Service 【发布时间】:2016-04-24 02:45:02 【问题描述】:

当从Activity 内部显示SnackBar 时,我有可用的rootView。但我需要从Service 内部显示SnackBar,我没有可用的View。我怎样才能做到这一点?

作为背景故事:一个活动启动一个服务来完成一项任务。 Service 需要根据情况显示SnackBar。我不想为此绑定到Service。那么我怎么能做到这一点呢?通常我可以显示Toast,但我需要用户能够阅读消息并确认。

【问题讨论】:

澄清一下,您是在询问是否能够在用户使用应用程序时或任何时候显示 Snackbar,即使应用程序已关闭? 【参考方案1】:

Snackbar 需要 View 才能显示,因此如果您想根据 Service 的状态在您的应用上显示快餐栏,您必须将其绑定到您的 Activity 或广播通过LocalBroadcastManager 发送消息并在您的View 上显示消息。

我认为没有其他方法可以解决它,您必须以某种方式与您的ActivityFragment 通信。

Snackbars 不像 Toasts 只需要一个上下文,所以如果你想在你的应用程序之外显示它,我相信你不能使用 android 提供的类。

来自design guidelines:

展示位置

Snackbars 出现在屏幕上大多数元素的上方,它们在 浮动操作按钮的高度。然而,它们在 比对话框、底部工作表和导航抽屉高。

这并不明确,但您可以得出结论,它只会显示在您的应用视图中。因此,再次,您必须以某种方式与您的可见视图进行通信。


广播消息的片段:

发件人(在您的服务上)

private void doSendBroadcast(String message) 
    Intent it = new Intent("EVENT_SNACKBAR");

    if (!TextUtils.isEmpty(message))
        it.putExtra(EXTRA_RETURN_MESSAGE,message);

    LocalBroadcastManager.getInstance(mContext).sendBroadcast(it);

接收者(在您的活动中)

private BroadcastReceiver mMessageReceiver = null;

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    // Other stuff.

    mMessageReceiver = new BroadcastReceiver() 
        @Override
        public void onReceive(Context context, Intent intent) 
            // Do something
        
    ;


@Override
public void onResume() 
    super.onResume();

    LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("EVENT_SNACKBAR"));

更多关于绑定服务here。

关于LocalBroadcastManagerhere on this question。

更新:您还可以使用EventBus 与您的可见 视图进行通信,因为它以发布者/订阅者的方式工作。您甚至可以利用Sticky events 的概念来确保一旦应用再次可见,Snackbar 就会显示出来。

看看我的this answer 了解如何使用事件总线。

【讨论】:

【参考方案2】:

您始终可以通过Service 中的LocalBroadcastManager 发送广播

LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent("SERVICE_DID_SOMETHING"));

然后在Activity 中使用BroadcastReceiver 来显示Snackbar

private final ServiceReceiver _serviceReceiver = new ServiceReceiver();

@Override
protected void onResume() 
    super.onResume();

    final IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("SERVICE_DID_SOMETHING");

    LocalBroadcastManager.getInstance(this).registerReceiver(_serviceReceiver, intentFilter);


@Override
protected void onPause() 
    super.onPause();

    try 
        LocalBroadcastManager.getInstance(this).unregisterReceiver(_serviceReceiver);
     catch (Exception ex) 
        Log.e(TAG, "Error unregistering ServiceReceiver", ex);
    


// region ServiceReceiver
private class ServiceReceiver extends BroadcastReceiver 

    @Override
    public void onReceive(Context context, Intent intent) 
        // TODO: Show your Snackbar here...
    

// endregion

如果需要,您可以使用您发送的Intent 传递其他数据,然后将其拉出BroadcastReceiver.onReceive(Context context, Intent intent)

【讨论】:

感谢您的帮助。 +1。我只能接受一个答案,所以我掷硬币。谢谢。【参考方案3】:

如何使用在多个活动中可见的应用程序上下文创建 Snackbar:https://***.com/a/37707741/1185087

【讨论】:

【参考方案4】:

使用 SDK 提供的默认 SnackBar 是不可能的,因为它总是需要一个视图。

为了达到您的目的,您可以使用一些模仿 SnackBar 的外部库,例如 this one

【讨论】:

会很感激有人投反对票的原因,除非是通过相互竞争的答案来寻求关注。 :) 这里经常发生这种情况。我讨厌它,它没有建设性。 不,@AndroidMechanic,您必须将视图传递给 SDK 或此库提供的 SnackBar。您将能够找到 2 个构造函数。 #1 new SnackBar.Builder(this) - this 作为活动。 #1 new SnackBar.Builder(getActivity().getApplicationContext(), root) - root 作为视图根

以上是关于从服务内部显示 Snackbar的主要内容,如果未能解决你的问题,请参考以下文章

从 runat 服务器 asp.net 内部添加

forward内部跳转 和redirect重定向跳转的区别

为啥有时小吃店会失败

Laravel ajax 帖子返回 500 内部服务器错误

通过公共网关服务对内部服务进行GraphQL订阅

自定义 Snackbar 无法正常工作