问题
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