公司項目有個需求,因爲是內部人員使用的APP,需要對撥出的電話做記錄,然後實時跟進每一撥電話是否接通或未接。首先想到的是PhoneStateListener這個類,但是實現後,發現“接通”這個判斷並不靠譜,然後想到一些APP在註冊或登錄的時候,能夠直接讀取短信並填充實現不用手動輸入驗證碼即可直接登錄的操作,最終發現了ContentObserver的妙用,並且非常簡單。
思路就是讀取手機通話記錄,判斷當前撥出的號碼與通話記錄中的第一條已撥電話記錄做比較,如果一致並且時長大於0既爲撥出已接通。
但是實現之後有個bug,就是onChange方法會調用多次,調用多次跟進上傳,最終在stackoverflow找到相關問題,並結合線程解決了這個問題。
直接上最後的代碼:
public class CallContentObserver extends ContentObserver {
public Logger gLogger = Logger.getLogger(this.getClass());
private static volatile int initialPos;
private static final Uri outSMSUri = CallLog.Calls.CONTENT_URI;
private Context context;
private String address;
private Handler mHandler; //更新UI線程
ExecutorService singleThreadExecuto
public CallContentObserver(Handler handler, Context context, String number) {
super(handler);
this.context = context;
this.address = number;
this.mHandler = handler;
singleThreadExecuto= Executors.newSingleThreadExecutor();
}
public void onChange(boolean selfChange) {
super.onChange(selfChange);
gLogger.debug("on change called");
queryLastCall();
}
//標記位置防止多次調用onchange
public int getLastCallId() {
try {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
return -1;
}
Cursor cur = context.getContentResolver().query(outSMSUri, null, null, null, CallLog.Calls.DATE + " desc");
cur.moveToFirst();
int lastMsgId = cur.getInt(cur.getColumnIndex("_id"));
return lastMsgId;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
protected void queryLastCall() {
singleThreadExecuto.execute(new Runnable() {
@Override
public void run() {
try {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
return;
}
Cursor cur =
context.getContentResolver().query(outSMSUri, null, null, null, CallLog.Calls.DATE + " desc");
if (cur.moveToNext()) {
if (initialPos != getLastCallId()) {
if(!TextUtils.isEmpty(address)){
if (cur.getString(cur.getColumnIndex("number")).contains(address)) {
int _id = cur.getInt(cur.getColumnIndex("_id"));
int type = cur.getInt(cur.getColumnIndex("type"));//通話類型,1 來電 .INCOMING_TYPE;2 已撥 .OUTGOING_;3 未接 .MISSED_
String number = cur.getString(cur.getColumnIndex("number"));// 電話號碼
int duration = cur.getInt(cur.getColumnIndex("duration"));//通話時長,單位:秒
String msgObj = "\nID:" + _id + "\n類型:" + type + "\n號碼:" + number + "\n時長:" + duration;
gLogger.debug(msgObj);
if(type==2){
if(duration>0){
mHandler.obtainMessage(answered, isSuccessSend).sendToTarget();
}else {
mHandler.obtainMessage(noAnswer, isSuccessSend).sendToTarget();
}
}
}
}
initialPos = getLastCallId();
}
}
cur.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
以上就是修復後的代碼,目前沒有發現什麼問題。
同理,獲取來電,或者短信記錄都可以用類似的方案解決