在通话详情界面,主要是完成2个功能,展示通话详情,删除该条通话记录。
CallDetailActivity界面如下,
CallDetailActivity的onCreate方法主要是加载界面布局。
主要在onResume方法中调用异步线程查询通话信息,调用流程图如下,
CallDetailActivity的onResume方法逻辑如下,
super.onResume();
getCallDetails();
getCallDetails方法如下,
CallLogAsyncTaskUtil.getCallDetails(this, getCallLogEntryUris(), mCallLogAsyncTaskListener);
getCallDetails方法 首先调用getCallLogEntryUris方法获取Uri对象,该方法如下,
final Uri uri = getIntent().getData(); // 单条通话信息
if (uri != null) {
// If there is a data on the intent, it takes precedence over the extra.
return new Uri[]{ uri };
}
// 多条通话信息
final long[] ids = getIntent().getLongArrayExtra(EXTRA_CALL_LOG_IDS);
final int numIds = ids == null ? 0 : ids.length;
final Uri[] uris = new Uri[numIds];
for (int index = 0; index < numIds; ++index) {
uris[index] = ContentUris.withAppendedId(
TelecomUtil.getCallLogUri(CallDetailActivity.this), ids[index]);
}
return uris;
TelecomUtil的getCallLogUri方法如下,
return hasReadWriteVoicemailPermissions(context) ? Calls.CONTENT_URI_WITH_VOICEMAIL : Calls.CONTENT_URI;
CONTENT_URI Uri定义如下,
public static final Uri CONTENT_URI = Uri.parse("content://call_log/calls");
就是calllog对应的Uri对象。
mCallLogAsyncTaskListener是CallLogAsyncTaskUtil内部接口CallLogAsyncTaskListener的匿名实现对象. CallLogAsyncTaskListener定义如下,
public interface CallLogAsyncTaskListener {
public void onDeleteCall();
public void onDeleteVoicemail();
public void onGetCallDetails(PhoneCallDetails[] details);
}
很明显,是三个回调接口,分别是异步查询完成通话记录/删除通话记录/删除Voicemail 之后的回调。
CallLogAsyncTaskUtil的getCallDetails方法逻辑如下,
1,构造线程池,
if (sAsyncTaskExecutor == null) {
initTaskExecutor();
}
initTaskExecutor方法如下,
sAsyncTaskExecutor = AsyncTaskExecutors.createThreadPoolExecutor();
2,调用AsyncTaskExecutor的submit方法开始查询。
主要看匿名内部类AsyncTask对象的doInBackground和onPostExecute方法。
doInBackground方法如下,
1,根据通话记录条数构造PhoneCallDetails组,
final int numCalls = callUris.length;
PhoneCallDetails[] details = new PhoneCallDetails[numCalls];
2,然后逐个调用getPhoneCallDetailsForUri方法 将查询信息 封装在 PhoneCallDetails中,
for (int index = 0; index < numCalls; ++index) {
details[index] = getPhoneCallDetailsForUri(context, callUris[index]);
}
3,最后返回的是PhoneCallDetails组,
return details;
当然, doInBackground方法是在后台线程中执行, onPostExecute方法在UI线程中执行,
onPostExecute方法如下,
if (callLogAsyncTaskListener != null) {
callLogAsyncTaskListener.onGetCallDetails(phoneCallDetails);
}
回调mCallLogAsyncTaskListener的onGetCallDetails方法,结果是PhoneCallDetails组。
CallLogAsyncTaskUtil的getPhoneCallDetailsForUri方法主要逻辑如下,
1,在Contacts2.db数据库里面查询call表单,获取cursor对象,
Cursor cursor = context.getContentResolver().query(
callUri, CallDetailQuery.CALL_LOG_PROJECTION, null, null, null);
2,查询通话记录信息,并且利用将这些信息封装在PhoneCallDetails中,
PhoneCallDetails details = new PhoneCallDetails(
context, number, numberPresentation, info.formattedNumber, isVoicemail);
PhoneCallDetails这个类比较简单,主要是一些变量,保存通话记录的信息,只有一个构造方法。
CallDetailActivity的mCallLogAsyncTaskListener的onGetCallDetails方法如下,
public void onGetCallDetails(PhoneCallDetails[] details) {
所有搜索结果都保存在PhoneCallDetails中。主要逻辑如下,
1,因为号码相同,因此首先显示第一条通话记录信息,
// We know that all calls are from the same number and the same contact, so pick the
// first.
PhoneCallDetails firstDetails = details[0];
mNumber = TextUtils.isEmpty(firstDetails.number) ? null : firstDetails.number.toString();
2,然后将其他PhoneCallDetails放入ListView中显示,
ListView historyList = (ListView) findViewById(R.id.history);
historyList.setAdapter(
new CallDetailHistoryAdapter(mContext, mInflater, mCallTypeHelper, details));
CallDetailHistoryAdapter还是比较简单的Adapter,简单的继承BaseAdapter,
public class CallDetailHistoryAdapter extends BaseAdapter {
其getView方法主要逻辑如下,
1,加载布局资源,获取PhoneCallDetails对象,因为第一条已经显示过了,因此需要减1,并且第一条结果直接返回了,
final View result = convertView == null
? mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false) : convertView;
PhoneCallDetails details = mPhoneCallDetails[position - 1];
2,为view赋值,例如,通话类型,通话时间,通话持续时间,
callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType, isVideoCall));
•••
dateView.setText(dateValue);
小结:
查询通话记录主要是异步查询加回调完成的,并且将信息封装在PhoneCallDetails对象中;
显示时利用CallDetailHistoryAdapter进行显示。
架构图如下,
有上个小节做铺垫,删除通话记录虽然也是异步的,但是容易很多了。
在CallDetailActivity的onMenuItemClick方法中,点击时,
1,如果是删除通话记录,
case R.id.menu_remove_from_call_log:
final StringBuilder callIds = new StringBuilder();
for (Uri callUri : getCallLogEntryUris()) {
•••
CallLogAsyncTaskUtil.deleteCalls(
this, callIds.toString(), mCallLogAsyncTaskListener);
break;
调用CallLogAsyncTaskUtil的deleteCalls方法进行删除。
2,删除Voicemail,
case R.id.menu_trash:
CallLogAsyncTaskUtil.deleteVoicemail(
this, mVoicemailUri, mCallLogAsyncTaskListener);
break;
这2个都是异步在数据库中删除数据,流程完全一样。
CallLogAsyncTaskUtil的deleteCalls方法流程图如下,
deleteCalls方法中的AsyncTask对象的doInBackground方法如下,
context.getContentResolver().delete(TelecomUtil.getCallLogUri(context),
CallLog.Calls._ID + " IN (" + callIds + ")", null);
return null;
直接对Contacts2.db数据库的calls进行删除操作。