简体   繁体   English

使用具有PhoneStateListener功能的BroadcastReceiver

[英]Using BroadcastReceiver with functionality of PhoneStateListener

I am trying to make a MissCall App which sends a message automatically when a miss call is received. 我正在尝试制作一个MissCall应用程序,它会在收到未接来电时自动发送消息。 I had completed my app and it worked fine ! 我已经完成了我的应用程序,它工作正常!
Here is the complete scenario : 这是完整的场景:
Problem : 问题:
The app was working fine but when i restarted the device the app didn't work ! 该应用程序工作正常,但当我重新启动设备时,该应用程序无法正常工作! . It only worked when i started my App atleast once after that it worked fine till it is switched off . 只有当我开始使用我的应用程序至少一次之后,它才能正常工作,直到关闭它才能正常工作。
Here is my code : 这是我的代码:

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;
            }
        }

    }



}

Solution : 方案:
I found out that the solution to this is to use BroadcastReceiver . 我发现解决方法是使用BroadcastReceiver So i registered a BroadcastReceiver but it didn't give me the functionality of PhoneStateListener 所以我注册了一个BroadcastReceiver,但它没有给我PhoneStateListener的功能
For eg I tried using the following code but it didn't work since BroadcastReceivers are only called when it receives something in contrast to PhoneStateListener which calls the method onCallStateChanged whenever there is a change in call state : 例如,我尝试使用以下代码,但它不起作用,因为BroadcastReceivers仅在收到与PhoneStateListener相反的东西时被调用,而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);
                }
            }

        }

    }
}

I also tried a work around but it showed negative results like : 我也试过一个解决方案,但它显示了负面结果,如:

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;
                }
            }

        }

    }
}

The above code fulfils all the requirements but it sends the in arithematic progression like if it is the first miss call it sends 1 and if it is tenth then it sends 10 messages ! 上面的代码满足了所有的要求,但它发送了一个arithematic进程,就好像它是第一次发送1的未命中调用,如果它是第十个则发送10条消息!
I seriously need help on this, Thank you in advance . 我真的需要帮助,谢谢你提前。


Edit 1 : 编辑1:
The problem is that every time when the onReceive() method is called a new TelphoneManager instance is created and registers as a listener to Phoone State . 问题是,每次调用onReceive()方法时,都会instance is created一个新的TelphoneManager instance is created并将其注册为Phoone State的监听器。
Solution : 方案:
I made every variable of the CallReceiverBroadcast class static ! 我将CallReceiverBroadcast类的每个变量都CallReceiverBroadcast 静态 and it solved the problem !! 解决了问题!! to an extent but still the service is called twice every time it means that some how there is 2 instance of the class registered as a listener but i don't know why. 在某种程度上,但是每次调用服务时都会调用两次,这意味着有两个类的实例如何被注册为监听器,但我不知道为什么。 Although i can work around it through some condition but it is causing unnecessary overhead and Anyone having a better solution will be highly Appreciated . 虽然我可以通过一些条件解决它,但它会导致不必要的开销, 任何拥有更好解决方案的人都会受到高度赞赏

这是因为一旦你得到了未接来电,那么你就是在TelephonyManager.CALL_STATE_IDLE阶段并且消息将发送到适当的消息,但你的服务正在运行模式,这就是为什么它会发送10个或多个短信。

In the first version, the listener is not auto restarted on boot (and also might be killed by the system) and which is why it didn't work on boot. 在第一个版本中,侦听器在引导时不会自动重新启动(也可能被系统杀死),这就是它在引导时无效的原因。 Also you forgot to unregister the listener. 此外,您忘记取消注册侦听器。

In your second version, onReceive() should be called whenever there is phone state changes, provided that your Manifest is setup correctly, like 在您的第二个版本中,只要您的Manifest设置正确,就会在有电话状态更改时调用onReceive() ,例如

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

However, Android may recycle the Broadcast receiver between calls to onReceive() , meaning that your checkIt variable may not be preserved between calls to onReceive() . 但是,Android可能会在调用onReceive()之间回收Broadcast接收器,这意味着在调用onReceive()之间可能无法保留checkIt变量。 You may need to use a static variable for it to work. 您可能需要使用静态变量才能工作。

In your third version, you are creating and registering multiple version of the call state listener whenever onReceive() is called. 在第三个版本中,只要调用onReceive() ,就会创建并注册多个版本的调用状态侦听器。 (Note that tm should point to the same instance of telephony manager), which may be why they are called multiple times. (注意,tm应指向电话管理器的同一实例),这可能是多次调用它们的原因。

Depending on how you turn the variables into static ones, the problem may not be solved since you may still be creating / registering new instances of CallStateListener , although you store it into a static variable. 根据您将变量转换为静态变量的方式,问题可能无法解决,因为您可能仍在创建/注册CallStateListener新实例,尽管您将其存储到静态变量中。

To solve these you should unregister the call state listener by overriding onDestroy() of the broadcast receiver 要解决这些问题,您应该通过覆盖广播接收器的onDestroy()来取消注册呼叫状态监听器

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

However please note that there is no guarentee that after onReceive() returns, the process hosting the receiver is not destroyed. 但是请注意,没有保证在onReceive()返回后,托管接收器的进程不会被破坏。 Your second version which performs all processing before onReceive() returns is preferable, if you can fix it. 如果您可以修复它,那么在onReceive()返回之前执行所有处理的第二个版本更可取。

尝试创建一个bootbroadcast接收器,并在其接收时启动您的服务以检测呼叫。这可确保您的服务在每次设备重启后自动激活。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM