android - 使用具有 PhoneStateListener 功能的 BroadcastReceiver

标签 android broadcastreceiver phone-state-listener

我正在尝试制作一个 MissCall 应用程序,它会在接到未接来电时自动发送一条消息。我已经完成了我的应用程序并且运行良好!
这是完整的场景:
问题:
该应用程序运行良好但当我重新启动设备时该应用程序无法运行!。它只在我至少启动我的应用程序一次后才工作,直到它关闭为止。
这是我的代码:

package com.example.misscallapp;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class Pref_Main extends PreferenceActivity {
    int checkIt = 0;
    TelephonyManager tm;
    CallStateListener callStateListener = new CallStateListener();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.prefs);
        tm = (TelephonyManager) getBaseContext().getSystemService(
                Context.TELEPHONY_SERVICE);
        tm.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
    }

    private class CallStateListener extends PhoneStateListener {

        @Override
        public void onCallStateChanged(int state, String incomingNumber) { 
           // Is called whenever there is a change in call state
            switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                // called when someone is ringing to this phone

                Toast.makeText(getBaseContext(), "Incoming: " + incomingNumber,
                        Toast.LENGTH_LONG).show();
                checkIt = 1;
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                checkIt = 0;
                break;
            case TelephonyManager.CALL_STATE_IDLE:
                if (checkIt == 1) {
                    Intent i = new Intent(getBaseContext(),MyService.class);
                    i.putExtra("phno", incomingNumber);
                    startService(i); // service that sends the SMS
                }
                break;
            }
        }

    }



}

解决方案:
我发现解决这个问题的方法是使用 BroadcastReceiver 。所以我注册了一个 BroadcastReceiver 但它没有给我 PhoneStateListener
的功能 例如,我尝试使用以下代码,但它不起作用,因为 BroadcastReceivers 仅在接收到与 PhoneStateListener 相比调用的内容时才被调用每当调用状态发生变化时调用 onCallStateChanged 方法:

package com.example.misscallapp;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class CallReceiverBroadcast extends BroadcastReceiver {
    int checkIt = 0;

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle extras = intent.getExtras();
        if (extras != null) {
            String state = extras.getString(TelephonyManager.EXTRA_STATE);
            String incomingNumber = extras.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);

            if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
                Toast.makeText(context , "Incoming: " + incomingNumber,
                        Toast.LENGTH_LONG).show();
                checkIt = 1;
            }

            if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
                // Call received
                checkIt = 0;
            }

            if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                if (checkIt == 1) {
                    Toast.makeText(context , "This is not shown ",
                            Toast.LENGTH_LONG).show();
                    Intent i = new Intent(context,MyService.class);
                    i.putExtra("phno", incomingNumber);
                    context.startService(i);
                }
            }

        }

    }
}

我也尝试了一种解决方法,但它显示了负面结果,例如:

package com.example.misscallapp;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class CallReceiverBroadcast extends BroadcastReceiver {
    int checkIt = 0;
    Context contextt;
    TelephonyManager tm;
    CallStateListener callStateListener = new CallStateListener();
    @Override
    public void onReceive(Context context, Intent intent) {
        contextt = context;
        tm = (TelephonyManager) context.getSystemService(
                Context.TELEPHONY_SERVICE);
        tm.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);

    }

    private class CallStateListener extends PhoneStateListener {

        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                // called when someone is ringing to this phone

                Toast.makeText(contextt, "Incoming: " + incomingNumber,
                        Toast.LENGTH_LONG).show();
                checkIt = 1;
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                checkIt = 0;
                break;
            case TelephonyManager.CALL_STATE_IDLE:
                if (checkIt == 1) {
                 //startting the service
                    break;
                }
            }

        }

    }
}

上面的代码满足了所有要求,但它发送的是等数级数,如果它是第一个未命中调用它发送 1,如果它是第十个则发送 10 条消息!
我真的需要帮助, 先感谢您 。


编辑 1 :
问题是,每次调用 onReceive() 方法时,都会创建一个新的 TelphoneManager 实例 并注册为 Phoone State 的监听器。
解决方案:
我将 CallReceiverBroadcast 类的每个变量设为 static !它在一定程度上解决了问题!!,但每次仍然调用两次服务,这意味着有些类的 2 个实例如何注册为监听器,但我不知道为什么。虽然我可以在某些情况下解决它,但它会导致不必要的开销,任何有更好解决方案的人都会受到高度赞赏

最佳答案

在第一个版本中,监听器不会在启动时自动重启(也可能被系统杀死),这就是它在启动时不起作用的原因。 你也忘了注销监听器。

在您的第二个版本中,只要您的 list 设置正确,只要手机状态发生变化,就应该调用 onReceive(),例如

  <receiver android:name=".CallReceiverBroadcast" >
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
  </receiver>

但是,Android 可能会在 onReceive() 调用之间回收广播接收器,这意味着您的 checkIt 变量可能不会在 onReceive() 调用之间保留。您可能需要使用静态变量才能使其正常工作。

在您的第三个版本中,每当调用 onReceive() 时,您都会创建并注册多个版本的调用状态监听器。 (注意 tm 应该指向同一个电话管理器实例),这可能就是它们被多次调用的原因。

根据您如何将变量转换为静态变量,问题可能无法解决,因为您可能仍在创建/注册 CallStateListener 的新实例,尽管您将其存储到静态变量中。

要解决这些问题,您应该通过覆盖广播接收器的 onDestroy() 来取消注册调用状态监听器

@Override
public void onDestroy() {
        tm.listen(callStateListener, PhoneStateListener.LISTEN_NONE);
}

但是请注意,不能保证在 onReceive() 返回后,托管接收方的进程不会被销毁。在 onReceive() 返回之前执行所有处理的第二个版本是更可取的,如果你能修复它的话。

关于android - 使用具有 PhoneStateListener 功能的 BroadcastReceiver,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22504869/

相关文章:

java - Android Studio 导入我自己的 .jar 文件

java - 如何在系统启动时启动一个服务并每1分钟重复一次

java - 包含 BroadCastReceiver 的服务无法正常运行

java - 即使在对话框显示并关闭后,如何保持底部控制栏始终隐藏?

c# - Android Compass 不指向北方并不断变化

Android 在广播接收器中异步拍照

java - 通话结束后重新开始 Activity 的正确方法

android - onCellLocationChanged 的​​问题

android - 在Android中检索来电的电话号码

android - 如何执行多个文件复制到共享集合下载,适用于 Android Q,Scoped Storage?