java.lang.NullPointerException: Attempt to invoke interface method 'int java.lang.CharSequence.length()' on a null object
환경 : Broadcast receiver call, 전화가 왔을때 그 전화번호를 받아와 로그에 출력하는 과정
오류원인 : incomingNumber 변수에 null 값이 들어가서 "Log.d();" 구문에 오류가 발생.
해결방안 : null 값이 들어가는 이유를 알아보고, 해결해야함.
1. 에러 코드
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); // 여기서 값을 제대로 받아오지 못함. String phone_number = PhoneNumberUtils.formatNumber(incomingNumber); // 그래서 phone_number 가 null 값이 되고, Log.d("phone call : ", incomingNumber); // 결국 Log가 null값을 찍어야하기 때문에 오류가 발생하는것!! |
2. 해결방안
null 값이 들어가는 이유는, manifest에 permission.READ_PHONE_STATE 권한이 있기 때문!!!
permission.READ_PHONE_STATE 라는 권한에 대해서 기존의 포스트에서도 두 번 수신된다는 언급이 있었는데,
나는 그걸 간과하고 두 번 수신되는 것에 대한 코드를 처리하지 않았음.
처음에 수신되면 incomingNumber에 값이 들어가는데, 두번째 수신이 될 때는 비워져서 들어가므로
최종적으로는 null 값이 반환되었던 것...!
따라서, 두 번 수신되는 것에 대한 코드 처리를 추가해줘야함.
(두 번 수신되는 이유에 대해서는 알 수 없음...)
또한, permission.READ_PHONE_STATE에 대한 권한 뿐만 아니라, permission.READ_CALL_LOG 권한에 대해서도 마찬가지임.
이 두개의 권한을 사용한다면, 꼭 수신에 관란 코드를 처리해야함.
3. 코드 수정
public void onReceive(Context context, Intent intent) {
|
수정합니다.
기존 코드 :
public class IncomingCallBroadcastReceiver extends BroadcastReceiver { private static String mLastState; public void onReceive(Context context, Intent intent) { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); Log.d("state : ", state); // RINGING 반환 if (state.equals(mLastState)) { return; } else { mLastState = state; } if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) { String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); String phone_number = PhoneNumberUtils.formatNumber(incomingNumber); Log.d("phone call : ", incomingNumber); } } } |
수정 코드 :
1) Manifest.xml
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/> <uses-permission android:name="android.permission.READ_CALL_LOG"/> |
2) MainActivity.java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.SYSTEM_ALERT_WINDOW) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CALL_LOG, Manifest.permission.SYSTEM_ALERT_WINDOW}, 1); } } } |
3) IncomingCallBroadcastReceiver.java
public class IncomingCallBroadcastReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) { String savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER"); } else{ String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE); String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER); 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 (number != null && !number.isEmpty() && !number.equals("null")) { //onCallStateChanged(context, state, number); Log.d("TEST :","NUMBER =>"+number); } } } } |
결론:
Manifest 추가 & MainAvtivity에서 permission을 허가받아야함 & 새로운 receiver 코드