Using BroadcastReceiver with functionality of PhoneStateListener

五迷三道 提交于 2019-12-09 00:57:15

问题


I am trying to make a MissCall App which sends a message automatically when a miss call is received.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 . So i registered a BroadcastReceiver but it didn't give me the functionality of PhoneStateListener
For e.g 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 :

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 !
I seriously need help on this, Thank you in advance .


Edit 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 .
Solution :
I made every variable of the CallReceiverBroadcast class static ! 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 .


回答1:


This is because of once you got the miss call then you are AT TelephonyManager.CALL_STATE_IDLE stage and message will send to appropriate message but your service is running mode that's Why it will send 10 or multiple sms.




回答2:


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

  <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(). 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. (Note that tm should point to the same instance of telephony manager), which may be why they are called multiple times.

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.

To solve these you should unregister the call state listener by overriding onDestroy() of the broadcast receiver

@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. Your second version which performs all processing before onReceive() returns is preferable, if you can fix it.




回答3:


try creating a bootbroadcast receiver,and in its on receive start your service to detect calls.this ensures that your service gets activated automatically after each device restart.



来源:https://stackoverflow.com/questions/22504869/using-broadcastreceiver-with-functionality-of-phonestatelistener

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!