无法对服务内部的广播接收器进行繁重的工作

如何解决无法对服务内部的广播接收器进行繁重的工作

我在Broadcast Receiver内部创建了一个Service Class(由于Android Broadcast receiver的限制Broadcast receiver停了一段时间,所以我创建了Background Service前景Service Notification Android Oreo中的限制= )。此Broadcast Receiver监听电话状态更改 IDLE,OFFHOOK,RINGING 。根据电话呼叫状态的变化(如果呼叫结束),我在游标中获取最后一个呼叫详细信息,并将该详细信息发送到Firebase Realtime Database中。一切工作正常,直到我对saveDatafromCursor()内部的PhoneStateListener Class方法发表评论(//)。 (我在保存数据方法之前写了一条Toast消息)。它工作得很好。而且我的服务效果很好。但是如果我取消对saveDatafromCursor()方法的注释,则通话结束后。我的服务停止(通知图标和吐司消息停止。我在真实设备中签入了)。 在不实施服务的情况下,我会将数据发送到运行良好的Firebase ,为什么我尝试将数据保存到Firebase时服务停止?

服务等级

public class HammerService extends Service {

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

        IntentFilter ifilter = new IntentFilter();
        ifilter.addAction(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED);

        registerReceiver(receiver,ifilter);

    }


    @Override
    public int onStartCommand(Intent intent,int flags,int startId) {

        String input = intent.getStringExtra("inputExtra");
        Intent notificationIntent = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,notificationIntent,0);

        Notification notification = new NotificationCompat.Builder(this,CHANNEL_ID)
                .setContentTitle("Hammer Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.ic_android)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(1,notification);

        //do heavy work on a background thread
        //stopSelf();
        return START_NOT_STICKY;

    }


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

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

    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context,final Intent intent) {
            String action = intent.getAction();
            if(action.equals("android.provider.Telephony.SMS_RECEIVED")){
                //action for sms received
            }
            else if(action.equals(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED)){
                runfirstTime(context,intent);
            }
        }
    };

    private void runfirstTime(Context context,Intent intent) {
        TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        MyPhoneStateListener customPhoneListener = new MyPhoneStateListener();

        telephony.listen(customPhoneListener,PhoneStateListener.LISTEN_CALL_STATE);

        Bundle bundle = intent.getExtras();
        String phone_number = bundle.getString("incoming_number");

        String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
        int state = 0;

        if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
            state = TelephonyManager.CALL_STATE_IDLE;
        }
        else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
            state = TelephonyManager.CALL_STATE_OFFHOOK;
        }
        else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
            state = TelephonyManager.CALL_STATE_RINGING;
        }

        if (phone_number == null || "".equals(phone_number)) {
            return;
        }

        customPhoneListener.onCallStateChanged(context,state,phone_number);
    }
}

PhoneStateListener类

public class MyPhoneStateListener extends PhoneStateListener {

    private static int lastState = TelephonyManager.CALL_STATE_IDLE;
    private static Date callStartTime;
    private static boolean isIncoming;

    static boolean calledAlready = false;

    private DatabaseReference databaseReference;
    private Context ctx;


    public void onCallStateChanged(Context context,int state,String phoneNumber) {
        if (lastState == state) {
            //No change,debounce extras
            return;
        }

        ctx = context;

        System.out.println("Number inside onCallStateChange : " + phoneNumber);

        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                isIncoming = true;
                callStartTime = new Date();

                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                if (lastState != TelephonyManager.CALL_STATE_RINGING) {
                    isIncoming = false;
                    callStartTime = new Date();

                }
                break;

            case TelephonyManager.CALL_STATE_IDLE:
                //Went to idle-  this is the end of a call.  What type depends on previous state(s)
                if (lastState == TelephonyManager.CALL_STATE_RINGING) {
                    //Ring but no pickup-  a miss
                    waitforlastcalllog();

                } else if (isIncoming) {

                    //  Toast.makeText(context,"Incoming " + phoneNumber + " Call time " + callStartTime,Toast.LENGTH_SHORT).show();

                    waitforlastcalllog();
                } else {

                    //  Toast.makeText(context,"outgoing " + phoneNumber + " Call time " + callStartTime +" Date " + new Date(),Toast.LENGTH_SHORT).show();

                    waitforlastcalllog();
                }

                break;
        }

        lastState = state;
    }

    private void waitforlastcalllog() {
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //String deviceMan = android.os.Build.MANUFACTURER;
                String deviceMan = Build.MANUFACTURER;

                String deviceName=deviceMan.toLowerCase();

                if(deviceName.equals("samsung"))
                {
                   // Toast.makeText(ctx,"dvv "+deviceMan,Toast.LENGTH_SHORT).show();
                    getCallLogs("samsung");
                }
                else
                {
                    getCallLogs("other");
                }


            }
        },500);

    }

    private void getCallLogs(String devicename) {

        ContentResolver cr = ctx.getContentResolver();
        if (ActivityCompat.checkSelfPermission(ctx,Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions,and then overriding
            //   public void onRequestPermissionsResult(int requestCode,String[] permissions,//                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        Cursor c = cr.query(CallLog.Calls.CONTENT_URI,null,null);

        if (c != null) {

            if(devicename.equals("samsung"))
            {
                if (c.moveToFirst()) { //starts pulling logs from last - you can use moveToFirst() for first logs
                    getCallDetails(c);
                }
            }else
            {
                if (c.moveToLast()) { //starts pulling logs from last - you can use moveToFirst() for first logs
                    getCallDetails(c);
                }
            }

            c.close();
        }
    }

    private void getCallDetails(Cursor c)
    {
        int totalCall=1;

        for (int j = 0; j < totalCall; j++) {

            String call_id = c.getString(c.getColumnIndexOrThrow(CallLog.Calls._ID));
            String phNumber = c.getString(c.getColumnIndexOrThrow(CallLog.Calls.NUMBER));
            String callDate = c.getString(c.getColumnIndexOrThrow(CallLog.Calls.DATE));
            String callDuration = c.getString(c.getColumnIndexOrThrow(CallLog.Calls.DURATION));
            Date dateFormat= new Date(Long.valueOf(callDate));
            String callDayTimes = String.valueOf(dateFormat);
            String callerName = c.getString(c.getColumnIndexOrThrow(CallLog.Calls.CACHED_NAME));


            String direction = null;
            switch (Integer.parseInt(c.getString(c.getColumnIndexOrThrow(CallLog.Calls.TYPE)))) {
                case CallLog.Calls.OUTGOING_TYPE:
                    direction = "OUTGOING";
                    break;
                case CallLog.Calls.INCOMING_TYPE:
                    direction = "INCOMING";
                    break;
                case CallLog.Calls.MISSED_TYPE:
                    direction = "MISSED";
                    break;
                case CallLog.Calls.VOICEMAIL_TYPE:
                    direction = "VOICEMAIL_TYPE";
                    break;
                case CallLog.Calls.REJECTED_TYPE:
                    direction = "REJECTED_TYPE";
                    break;
                case CallLog.Calls.BLOCKED_TYPE:
                    direction = "BLOCKED_TYPE";
                    break;
                case CallLog.Calls.ANSWERED_EXTERNALLY_TYPE:
                    direction = "ANS EXT TYPE";
                    break;
                default:
                    break;
            }

            c.moveToPrevious(); // if you used moveToFirst() for first logs,you should this line to moveToNext

            Toast.makeText(ctx,phNumber + callDuration + callDayTimes + direction +callerName,Toast.LENGTH_LONG).show(); // you can use strings in this line
            saveDatafromCursor(phNumber,callDuration,callDayTimes,direction,callerName);
        }
    }


    private void saveDatafromCursor(String phNumber,String callDuration,String callDayTimes,String direction,String callername)
    {
        ModelCursor mc=new ModelCursor();

        mc.setPhoneNumber(phNumber);
        mc.setCallDuration(callDuration);
        mc.setCallDayTimes(callDayTimes);
        mc.setDirection(direction);

        if(callername==null)
        {
            callername="Not in Contacts";
        }

        mc.setCallUsername(callername);


        if (!calledAlready) {
            FirebaseDatabase.getInstance().setPersistenceEnabled(true);
            calledAlready = true;
        }

        FirebaseDatabase database = FirebaseDatabase.getInstance();
        databaseReference = database.getInstance().getReference().child("Call-Details-X");
        String key = databaseReference.push().getKey();

        String android_id = Settings.Secure.getString(ctx.getContentResolver(),Settings.Secure.ANDROID_ID);

        Date date=new Date();

        SimpleDateFormat timeStampFormatsearch = new SimpleDateFormat("dd-yyyy-MM");
        String dateofcall = timeStampFormatsearch.format(date);


        databaseReference.child(android_id).child(dateofcall).child(key).setValue(mc).addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {

            }
        });
    }

}

Logcat-错误

2020-08-12 10:03:33.217 5151-5151/com.fooding.callhammer E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.fooding.callhammer,PID: 5151
    com.google.firebase.database.DatabaseException: Calls to setPersistenceEnabled() must be made before any other usage of FirebaseDatabase instance.
        at com.google.firebase.database.FirebaseDatabase.assertUnfrozen(com.google.firebase:firebase-database@@17.0.0:316)
        at com.google.firebase.database.FirebaseDatabase.setPersistenceEnabled(com.google.firebase:firebase-database@@17.0.0:284)
        at com.fooding.callhammer.MyPhoneStateListener.saveDatafromCursor(MyPhoneStateListener.java:214)
        at com.fooding.callhammer.MyPhoneStateListener.getCallDetails(MyPhoneStateListener.java:191)
        at com.fooding.callhammer.MyPhoneStateListener.getCallLogs(MyPhoneStateListener.java:138)
        at com.fooding.callhammer.MyPhoneStateListener.access$000(MyPhoneStateListener.java:26)
        at com.fooding.callhammer.MyPhoneStateListener$1.run(MyPhoneStateListener.java:104)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2020-08-12 10:03:33.446 2016-2122/system_process E/InputDispatcher: channel '276f02e com.fooding.callhammer/com.fooding.callhammer.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
2020-08-12 10:03:36.556 2016-2197/system_process E/TaskPersister: File error accessing recents directory (directory doesn't exist?).
2020-08-12 10:03:48.799 2016-2041/system_process E/memtrack: Couldn't load memtrack module
2020-08-12 10:03:49.499 2016-2048/system_process E/BatteryExternalStatsWorker: no controller energy info supplied for wifi
2020-08-12 10:04:00.018 2016-2041/system_process E/memtrack: Couldn't load memtrack module

解决方法

摘自文档:服务在其托管过程的主线程中运行;除非另行指定,否则该服务不会创建自己的线程,也不会在单独的进程中运行。您应该在服务内的单独线程上运行任何阻止操作,以避免应用程序无响应(ANR)错误。我认为这就是为什么您不能在Service类中完成“繁重”工作的原因。我没有检查您的代码,但是您可以做两件事:

1。)在创建时在服务中创建新线程,然后执行“繁重的工作”(不要忘记停止它)。 https://developer.android.com/guide/components/services

2。)扩展JobIntentService类,尝试一下。然后覆盖函数onHandleWork(intent),在此开始“繁重的”工作。 https://developer.android.com/reference/androidx/core/app/JobIntentService

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-