双击退出app问题(System.exit(0)),服务重启

1、最近在写一个基本都在本地操作的app的时候,由于最后我要把本地app里面的基本所有东西要上传到服务器的数据库里面。并且要上传大量图片,所以相当耗时并且会挡住屏幕。要想不挡住屏幕就开启线程或者是服务,当然上传本身就是在一个线程里面。所以我不打算再继续开线程了,于是我就把这个上传操作写在了服务里面。。那么问题就来了。

app习惯性的大家都是双击退出,那我就在MainActivity的onDestory里面关闭服务,可是我在服务的onDestroy里面打log,他就是在双击退出之后不走这个,并且在Activity的OnDestroy里面的任何东西都没有,我慢慢推理和验证发现是因为我在双击的地方走了System.exit(0);那么就直接关闭组件和其他资源了。服务也被关闭了,但是服务的onDestroy没有打log。但是如果把这句代码屏蔽的话,确实关闭服务的时候是正常的并且有日志可以看见,但是问题就来了。那么app虽然是界面以及关闭了,但是却没有释放资源。这样虽然看起来是没有什么问题,但是仍然还占用内存资源,外行人虽然看不出来,但是肯定是会被同行鄙视的,,,,,。。!所以肯定是要调System.exit(0);或者是类似关闭整个app并释放资源的方法。

2、问题又来了,我调玩这个System.exit(0);之后就发现服务过了几秒钟又重新走了onCreate()和onStart()方法。由于我写的代码中我用activity向Service中传递了数据,那么onStratCommand哪里就会报nullPointEx,我的天,虽然用起来不会有什么不良影响,,但是我的亲哥,,app退出之后还崩掉了,,你能忍???我肯定是不会忍的,,,继续找解决办法。。。

3、我找了几十分钟,,想到了一个办法,就是在双击退出的地方我调一个方法,这个方法里面做一个判断。服务是否还在运行,如果还在运行的话就先关闭服务再finish()和System.exit(0)。但是结果还是一样,服务的onDestroy还是没走,但是服务没有重新开启了。。。因为我在服务的OnDestroy里面写了一些方法必须要走,不走我就心态要蹦。。。后来,,机制如我:我还是用同一个方法,我在里面写一个handler.postDelay,先来一个判断,服务是否正在运行,,,如果没有正在运行,那么我就直接掉finish()和System.exit(0);,,,如果服务正在运行,那么我就先关闭服务再走finish(),然后在finish()后面来一个handler.postDelay,把System.exit(0);写在里面。。。我delay了一秒钟,,,是正常运行的。。。。


至于为什么服务会重启,因为onStartCommand的返回值问题,要是你想深究可以直接去查相关知识。。。


补充:最后我进一步学习service找到重启的原因了,确实是onStartCommand的返回值原因导致的;

public class TestService extends Service {

    private static final String TAG = "cy====TestService";

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

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand()");
        Log.i(TAG, "flags:" + flags);
        Log.i(TAG, "startId:" + startId);
//        boolean b = stopSelfResult(startId);
//
//        if (b){
//            Log.i(TAG, "true");
//        }else {
//            Log.i(TAG, "false");
//        }

        //=========================flags==================================
        /**
         * flag表示启动请求时是否有额外数据,默认是0代表没有额外的数据传递进来。还有两个选项:
         * (1)START_FLAG_RETRY 值是2,代表当onStartCommand调用后一直没有返回值时,会尝试重新去调用onStartCommand()。
         * (2)START_FLAG_REDELIVERY 值是1,代表了onStartCommand方法的返回值为START_REDELIVER_INTENT,而且在上
         *      一次服务被杀死前会去调用stopSelf方法停止服务。其中START_REDELIVER_INTENT意味着当Service因内存不足而被
         *      系统kill后,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand(),此时Intent时有值的。
         */

        //====================================startId=====================================

//     startId:指明当前服务的唯一ID,与stopSelfResult (int startId)配合使用,stopSelfResult 可以更安全地根据ID停止服务。

        //========================onStartCommand的返回值=============================
        /**
         * (1)START_STICKY:粘性
         *     当Service因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试重新创建此Service,一旦创建成功后将回
         *   调onStartCommand方法,但其中的Intent将是null,除非有挂起的Intent,如pendingintent,这个状态下比较适用于不执行
         *   命令、但无限期运行并等待作业的媒体播放器或类似服务。
         *
         * (2)START_NOT_STICKY:不粘性
         *      当Service因内存不足而被系统kill后,即使系统内存再次空闲时,系统也不会尝试重新创建此Service。除非程序中再次调用
         *    startService启动此Service,这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。
         *
         * (3)START_REDELIVER_INTENT:重新传送Intent
         *       当Service因内存不足而被系统kill后,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand(),任
         *     何挂起 Intent均依次传递。与START_STICKY不同的是,其中的传递的Intent将是非空,是最后一次调用startService中的
         *     intent。这个值适用于主动执行应该立即恢复的作业(例如下载文件)的服务。
         */

        /**
         *
         * 总结:上拉杀死app的时候,有时候系统有可能在MainActivity的onDestroy之前就完成了杀死service的操作,因为不是你主动和service内部调用的service的onDestroy
         * 方法,所以不会走service的onDestroy内容。点击清空来杀死app的时候一定会走和先走MainActivity的onDestroy方法,这个时候如果你调用的stopService,那么你会在系统之前杀
         * 死service,所以会走service的onDestroy的内容。无论是上拉还是清空内存的方式来杀死app基本都会走(我发现是95%以上)MainActivity的onDestroy方法和肯定停止服务,
         * 但是service的onDestroy里面的代码块是否会走就要看杀死app的方式(是否能外面或内部调用到Service的onDestroy方法)。
         *
         * onStartCommand的返回值不一样只是是否会重启service的区别;但是无论是上拉杀死app还是清理内存来杀死app无论返回什么都不会重启service,只有在System.exit(0)的时候
         * 返回START_REDELIVER_INTENT和START_STICKY会重启service,返回START_NOT_STICKY不会重启service。如果返回默认值,有的手机(比如:mate8)会重启有的手机(比如:redMi
         *  Note4x)不会重启。我觉得有的时候修改了默认值,我用谷歌模拟器测试的时候返回默认值是重启的。所以我觉得需求明确的话不要返回默认值。
         *
         *  补充:用红米note4X无论返回什么值都不重启。
         *
         */

        Log.i(TAG, "默认返回值是:" + super.onStartCommand(intent, flags, startId));
        return START_NOT_STICKY;//不重启
//        return super.onStartCommand(intent, flags, startId);//默认(其实是1=START_STICKY)
//        return START_STICKY;//重启
//        return START_REDELIVER_INTENT;重启
    }

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

}

我在MainActivity里面的调用System.exit(0);导致的,然后如果调用了Sys这个退出的话,MainActivity的onDestroy()里面的代码块也不会走了,所以要执行的代码块可以放在这句代码之前就可以了。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值