Android 时间到了需要不同的界面都要显示抢红包

2019-09-25  本文已影响0人  一个冬季
参考文章

Android 8.0以后使用后台Service服务JobIntentService的使用
Android O 行为变更适配方案

博文修改

2019-10-21 修改该博文

需求描述

公司需要做一个抢红包的功能,然后只要用户在这个APP内,不管你在APP的哪个界面,你都要弹出红包出来。

开始骚操作

我最开始的想法是这样的,我想创建红包activity当成一个dialog来使用,因为我看到也有很多人这样说。然后在主Activity里面开启一个service,当然不要忘记destory的生活关闭它。

遇到的问题

1、如果直接在service启动Activity是无法启动的,你需要这样写代码才可以启动

Intent intentv = new Intent(RedEnvelopesService.this, RedEnvelopesActivity.class);
                       intentv.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
                        startActivity(intentv);

 <!--红包的activity  singleTop一直启动相同的界面    excludeFromRecents 表示这个Activity不会显示在最近列表里面。-->
       <activity android:name=".activity.shop.RedEnvelopesActivity"
            android:screenOrientation="portrait"
            android:theme="@style/Redenvelopes.NoactonBar"/>

2、启动后,发现activity启动后,不是透明的背景,然后我就做了下面的事情,将背景弄为透明

    <style name="Redenvelopes.NoactonBar"  parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowBackground">@color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>

3、Service里面的倒计时

    private Disposable disposable;
    final int SECONDSEND = 30;
    volatile int counDown = 0;
    //开始倒计时
    private void counDownTime() {
        Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.newThread())
                .filter(new Predicate<Long>() {
                    @Override
                    public boolean test(Long aLong) throws Exception {
                        counDown = counDown + 1;
                        if (counDown>=SECONDSEND){//只有满了30秒才会执行后面的操作
                            counDown = 0;
                            return true;
                        }
                        return false;
                    }
                }).subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable = d;
                    }

                    @Override
                    public void onNext(Long aLong) {
                     //时间到了启动Activity
                     Intent intentv = new Intent(RedEnvelopesService.this, RedEnvelopesActivity.class);
                     intentv.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
                     startActivity(intentv);
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {
                        Log.i(TAG,"onComplete");
                    }
                });
    }

在service里面,我很开心的启动了红包activity,只要时间一到就开启红包activity,就在我开心之余,我按下了Home键,到了某个时间点,它又自动回到APP内(帮你吊起APP),打开红包activity,对于这么恶心的问题肯定是不行的,所以要放弃上面的步骤方法

新思路

我们继续秉承着在service开启倒计时的方案,我们到了某个时间点,就本地广播一次,我们可以再主activity里面监听广播,监听到后,我们拿当前最前面的一个activity来帮我们开启一个popuwindow。

1、首先需要在service开启广播,如果到了某个时间的点,就本地广播

 Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.newThread())
                .filter(new Predicate<Long>() {
                    @Override
                    public boolean test(Long aLong) throws Exception {
                        counDown = counDown + 1;
                        if (counDown>=SECONDSEND){//只有满了30秒才会执行后面的操作
                            counDown = 0;
                            return true;
                        }
                        return false;
                    }
                }).subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable = d;
                    }

                    @Override
                    public void onNext(Long aLong) {
                        Log.i(TAG, "onNext");
                        //发送广播
                        Intent intent = new Intent(START_REDENVELOPES_ACTION);
                        LocalBroadcastManager.getInstance(RedEnvelopesService.this).sendBroadcast(intent);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.i(TAG,e.getLocalizedMessage());
                    }

                    @Override
                    public void onComplete() {
                    }
...省略代码

2、创建一个popuwindow,获取最前面的一个Activity进行展示,有一点需要注意,Popuwindow里面的activity需要采用弱引用

...省略代码
    private View drowView;
    private PopupWindow popupWindow;
    private WeakReference<SPBaseActivity> weakReference;
    public RedEnvelopesPopuWindow(BaseActivity activity) {
        weakReference = new WeakReference<BaseActivity >(activity);//注意这里
        drowView = weakReference.get().getWindow().getDecorView();
    }

/**
     * @date :2019/9/18 0018
     * @author : gaoxiaoxiong
     * @description:销毁popuwindow
     **/
    public void onDestoryPopuWindow(){
        activityWeakReference.clear();
        redEnvelopesListenerWeakReference.clear();
        this.onRedEnvelopesListener = redEnvelopesListenerWeakReference.get();
        popupWindow.dismiss();
    }

3、在MainActivity接收广播,注意需要在destory的时候移除广播监听

    private RedEnvelopesPopuWindow popuWindow;//popuwindow
    private Activity preActivity;//前一个Activity
    @Override
    public void initData() {
        //注册广播监听
        if (localBroadcastReceiver == null) {
            localBroadcastReceiver = new LocalBroadcastReceiver();
            localBroadcastReceiver.setOnClassNameListener(new LocalBroadcastReceiver.OnBroadCastNameListener() {
                @Override
                public void onBroadCastName(String name, Intent intent123) {
                   if (preActivity!=null){
              //获取到当前的popuwindow,注意这里我们需要获取一个弱引用给currentActivity 
                       Activity currentActivity = AppActivityManager.getInstance().currentActivity();
                       if (popuWindow == null) {
                              popuWindow = new RedEnvelopesPopuWindow(currentActivity);
                           }
                       preActivity = AppActivityManager.getInstance().currentActivity();
                   }
                    popuWindow.showPowuWindow();
                }
            });
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(START_REDENVELOPES_ACTION);
            LocalBroadcastManager.getInstance(this).registerReceiver(localBroadcastReceiver, intentFilter);
        }
    }

特别注意:AppActivityManager.getInstance().currentActivity(),拿到的是一个弱引用

其它知识点小结

1、采用Observable.interval开启1秒循环,如果想终止的话,需要调用disposable.dispose()方法。如果没有终止,继续调用Observable.interval来开启倒计时,会开启2个线程,你会看到aLong里面会出现一个大的值,一个小的值,所以你要关闭一个

.filter(new Predicate<Long>() {
                    @Override
                    public boolean test(Long aLong) throws Exception {
                        counDown = counDown + 1;
                        if (counDown>=SECONDSEND){//只有满了30秒才会执行后面的操作
                            counDown = 0;
                            return true;
                        }
                        return false;
                    }
                })

特别注意:
1、android 8.0过后,有对service做限制操作,我们不可以按下home按键,然后启动后台service,这样的启动方式会直接导致我们崩溃。如果我们想按下home按键,想启动service,我们需要调用 Context.startForegroundService()启动,并且在service里面调用startForeground()且通知栏有Notification显示该Service正在运行
2、如果采用JobService来执行任务,是有时间限制的,不管它是处于前台还是后台,因此 Job Scheduler 适用于短耗时的后台任务,不适用于连续的长时间的后台服务。

上一篇 下一篇

猜你喜欢

热点阅读