Android 广播、服务、对话框直接交互

本文介绍如何在移动端应用中实现一个定时访问后台的服务,并在特定条件下展示对话框,探讨了不同实现方案及其优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前两天公司给了一个新需求,就是要求移动端内部有个开关,定时访问后台,当后台返回数据为true时展示对话框,但是不让用户知道。本来跟大佬说加个推送更方便快捷简单,还减少服务器压力。。。但是老板不允许,本着老板就是上帝的态度,那就做呗。

既然不然用户感知那就用个Service吧,后台运行就行了。说搞就搞,先写一个服务

public class MyService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

既然要定时访问数据那就再来个计时线程吧,然后十秒访问一次

   Handler handler=new Handler();
    Runnable runnable=new Runnable() {
        @Override
        public void run() {
            handler.postDelayed(runnable,10000);
        }
    };

收到消息后需要弹出对话框,那肯定需要广播了,那就写一个广播吧,收到广播后弹出对话框

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, Intent intent) {
        AlertDialog.Builder dialog = new AlertDialog.Builder(context);
        dialog.setTitle("我是Title");
        dialog.setMessage("我是测试的消息内容");
        dialog.setNegativeButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(context, "点击了确定", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        });
        dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(context, "点击了取消", Toast.LENGTH_SHORT).show();
                dialog.dismiss();
            }
        });
        dialog.show();
    }
}

然后在在服务里写一个请求方法,我这里做测试就不写请求了,就写个方法模拟一下,在计时线程中调用该方法,并传递i,用于测试判断是否获取到了值

  private void getServer(int i) {
        Intent intent=new Intent(this,MyReceiver.class);
        intent.putExtra("test",i);
        sendBroadcast(intent);
    }

然后在广播了增加判断,当i==20的时候弹出对话框

点击运行,你会发现项目崩溃了,看日志会出现这个异常

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?

报错异常是因为对话框的创建是依附与Activity界面存在的,我们在广播中传递给Dialog的Context并没有界面,而是一个广播的上下文,并不存在界面,所以报了这个错误,要怎么解决呢?

其实也很简单,我们只需要在AndroidManifest.xml文件里加入申请悬浮窗权限,然后在dialog.show之前加入这句代码

 

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
//alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
//google规定O以上需要改成这个 TYPE_APPLICATION_OVERLAY
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);

这样就可以正常显示了。

如果你不想这么麻烦,也可以使用一个本地广播直接在Activity里创建一个内部类,然后在使用,不过使用有点不一样,发送消息要这样,LocalBroadcastManager,使用这个安全性更高,也便于管理

 //发送广播
 LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
 Intent intent = new Intent("com.example.testbradcasereceiver.myreceiver");
 intent.putExtra("test", i);
 localBroadcastManager.sendBroadcast(intent);

然后在activity里注册广播和添加广播接收器(代码一样我就不重复写了)

//注册广播
myReceiver = new MyReceiver();
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.testbradcasereceiver.myreceiver");
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(myReceiver, intentFilter);

效果是一样的,只是这个你在按Home键时这个是不可见的,而悬浮窗那种回到桌面也是可见的。两中方式各有优缺点,看需求吧

最后在说一句,为了避免溢出请注意注销,,,我这里都没写哦

 

 

Github下载地址

优快云下载

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值