我正在研究调用日志应用程序的示例。在此应用程序中,我的片段在列表中显示Dialed Type调用。在每个列表项中,它显示来自联系人的照片,编号,名称和时间。它工作正常但滚动时滞后。
片段代码:
package com.example.vl.calllogs;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.CallLog;
import android.provider.ContactsContract;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.View;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.ResourceCursorAdapter;
import android.widget.TextView;
import org.w3c.dom.Text;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by vl on 12/29/2015.
*/
public class TabDialedFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
CursorAdapter mAdapter;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setEmptyText("No Dialed Numbers");
mAdapter = new MyCursorAdapter(getActivity(), R.layout.fragment_tab_dialed, null, 0);
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
}
private static final String[] PROJECTION = {
CallLog.Calls._ID,
CallLog.Calls.DATE,
CallLog.Calls.CACHED_NAME,
CallLog.Calls.CACHED_PHOTO_ID,
CallLog.Calls.NUMBER,
CallLog.Calls.DURATION
};
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri baseUri = CallLog.Calls.CONTENT_URI;
String selection = CallLog.Calls.TYPE + "= 2";
return new CursorLoader(getActivity(), baseUri, PROJECTION,selection, null, CallLog.Calls.DATE + " DESC" );
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
class MyCursorAdapter extends ResourceCursorAdapter{
MyCursorAdapter(Context context, int layout, Cursor cursor, int flags ){
super(context, layout,cursor,flags);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView name = (TextView) view.findViewById(R.id.name);
String nameString = cursor.getString(cursor.getColumnIndex(CallLog.Calls.CACHED_NAME));
if(nameString == null || "".equals(nameString.trim())){
name.setText("Unknown");
}else{
name.setText(nameString);
}
TextView time = (TextView) view.findViewById(R.id.time);
String timeS = cursor.getString(cursor.getColumnIndex(CallLog.Calls.DATE));
Date callDayTime = new Date(Long.valueOf(timeS));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm");
String str = simpleDateFormat.format(callDayTime);
String durationS = cursor.getString(cursor.getColumnIndex(CallLog.Calls.DURATION));
time.setText(String.format(getActivity().getResources().getString(R.string.thirdLine), str, durationS));
TextView number = (TextView) view.findViewById(R.id.number);
String numberS = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
number.setText(numberS);
int contactID = getContactIDFromNumber(numberS);
ImageView imageView = (ImageView) view.findViewById(R.id.imageView);
imageView.setImageBitmap(getPhoto(contactID+""));
}
public int getContactIDFromNumber(String contactNumber)
{
contactNumber = Uri.encode(contactNumber);
int phoneContactID = -1;
Cursor contactLookupCursor = getActivity().getContentResolver().query(Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,contactNumber),new String[] {ContactsContract.PhoneLookup.DISPLAY_NAME, ContactsContract.PhoneLookup._ID}, null, null, null);
while(contactLookupCursor.moveToNext()){
phoneContactID = contactLookupCursor.getInt(contactLookupCursor.getColumnIndexOrThrow(ContactsContract.PhoneLookup._ID));
}
contactLookupCursor.close();
return phoneContactID;
}
private Bitmap getPhoto(String id){
Bitmap photo = null;
try{
InputStream inputStream = ContactsContract.Contacts.openContactPhotoInputStream(
getActivity().getContentResolver(),
ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, new Long(id).longValue()));
if(inputStream != null)
photo= BitmapFactory.decodeStream(inputStream);
}catch (Exception e){
}
return photo;
}
}
}
我觉得这可能是从联系人中获取照片的有效方式的问题。在这里我首先获取contact_id,然后使用联系人ID查询照片。这是正确的方法吗?
上次查询不是异步工作。要做异步我该怎么办?
答案 0 :(得分:2)
您应该修复bindView
上的三个主要性能问题。
对private Bitmap getPhoto
的调用是SQLite操作,后跟磁盘加载操作。这需要几毫秒才能完成,并且肯定会落后于用户界面。
坏消息是后台线程图像加载和缓存是一个非常复杂的主题,很难正确编码。
好消息是,如今我们拥有大量优秀的图书馆,可以帮助您。以下是使用Picasso library
加载它的代码Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
Picasso.with(getActivity()).load(uri).into(imageView);
调用public int getContactIDFromNumber
也在进行SQLite查询,而且速度也很慢。
不幸的是,我对你应该如何修复它没有任何重大建议。这是一个缓慢的操作,你应该在后台线程中做。它将是一个主要的重构,使它在适配器内部工作。
我的建议是扩展CursorLoader
并在完成加载游标(但仍然在后台线程上)后执行以执行所有这些查询并将其保留在某些HashMap
次要问题:
findViewById(int)
的所有调用。bindView
内创建新对象。例如,对于整个类,您应该只有1 private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm");
并且始终使用相同的实例。也只有1 Date
个适配器对象,只需调用callDayTime.setTime(Long.valueOf(timeS));
希望它有所帮助。