Android 滚动时调用列表视图延迟

Android 滚动时调用列表视图延迟,android,loader,calllog,Android,Loader,Calllog,我正在开发调用日志应用程序示例。在这个应用程序中,我的片段在列表中显示拨号类型的呼叫。在每个列表项中,它显示联系人的照片、号码、姓名和时间。它工作正常,但滚动时会出现延迟 片段代码: package com.example.vl.calllogs; import android.content.ContentUris; import android.content.Context; import android.database.Cursor; import android.graphics

我正在开发调用日志应用程序示例。在这个应用程序中,我的片段在列表中显示拨号类型的呼叫。在每个列表项中,它显示联系人的照片、号码、姓名和时间。它工作正常,但滚动时会出现延迟

片段代码:

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;
        }

    }

}
package com.example.vl.calllogs;
导入android.content.ContentUris;
导入android.content.Context;
导入android.database.Cursor;
导入android.graphics.Bitmap;
导入android.graphics.BitmapFactory;
导入android.net.Uri;
导入android.os.Bundle;
导入android.provider.CallLog;
导入android.provider.contacts合同;
导入android.support.v4.app.ListFragment;
导入android.support.v4.app.LoaderManager;
导入android.support.v4.content.CursorLoader;
导入android.support.v4.content.Loader;
导入android.util.Log;
导入android.view.view;
导入android.widget.CursorAdapter;
导入android.widget.ImageView;
导入android.widget.ResourceCursorAdapter;
导入android.widget.TextView;
导入org.w3c.dom.Text;
导入java.io.InputStream;
导入java.text.simpleDataFormat;
导入java.util.Date;
/**
*由vl于2015年12月29日创建。
*/
公共类TabDialedFragment扩展ListFragment实现LoaderManager.LoaderCallbacks{
游标适配器;
@凌驾
已创建ActivityState上的公共无效(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
setEmptyText(“无已拨号码”);
mAdapter=new MyCursorAdapter(getActivity(),R.layout.fragment\u tab\u拨号,null,0);
setListAdapter(mAdapter);
getLoaderManager().initLoader(0,null,this);
}
私有静态最终字符串[]投影={
CallLog.Calls.\u ID,
CallLog.Calls.DATE,
CallLog.Calls.CACHED_名称,
CallLog.Calls.CACHED_PHOTO_ID,
CallLog.Calls.NUMBER,
CallLog.Calls.DURATION
};
@凌驾
公共加载器onCreateLoader(int-id,Bundle-args){
Uri baseUri=CallLog.Calls.CONTENT\u Uri;
字符串选择=CallLog.Calls.TYPE+“=2”;
返回新的游标装入器(getActivity(),baseUri,PROJECTION,selection,null,CallLog.Calls.DATE+“DESC”);
}
@凌驾
public void onLoadFinished(加载器、光标数据){
mAdapter.swapCursor(数据);
}
@凌驾
公共void onLoaderReset(加载器){
mAdapter.swapCursor(空);
}
类MyCursorAdapter扩展了ResourceCursorAdapter{
MyCursorAdapter(上下文上下文、整型布局、光标、整型标志){
超级(上下文、布局、光标、标志);
}
@凌驾
公共void bindView(视图、上下文上下文、光标){
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(“未知”);
}否则{
name.setText(名称字符串);
}
TextView时间=(TextView)view.findViewById(R.id.time);
字符串时间=cursor.getString(cursor.getColumnIndex(CallLog.Calls.DATE));
Date CallDaily=新日期(长值(次));
SimpleDataFormat SimpleDataFormat=新的SimpleDataFormat(“EEE,d MMM yyyy HH:mm”);
String str=simpleDataFormat.format(callDaily);
字符串持续时间=cursor.getString(cursor.getColumnIndex(CallLog.Calls.DURATION));
time.setText(String.format(getActivity().getResources().getString(R.String.thirdLine),str,durationS));
TextView编号=(TextView)view.findViewById(R.id.number);
字符串编号=cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
number.setText(数字);
int contactID=getContactIDFromNumber(数字);
ImageView=(ImageView)view.findViewById(R.id.ImageView);
setImageBitmap(getPhoto(contactID+“”));
}
public int getContactIDFromNumber(字符串contactNumber)
{
contactNumber=Uri.encode(contactNumber);
int phoneContactID=-1;
Cursor contactLookupCursor=getActivity().getContentResolver().query(Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT\u FILTER\u Uri,contactNumber),新字符串[]{ContactsContract.PhoneLookup.DISPLAY\u NAME,ContactsContract.PhoneLookup.\u ID},null,null,null);
while(contactLookupCursor.moveToNext()){
phoneContactID=contactLookupCursor.getInt(contactLookupCursor.getColumnIndexOrThrow(ContactsContact.PhoneLookup;
}
contactLookupCursor.close();
返回电话联系人ID;
}
私有位图getPhoto(字符串id){
位图照片=空;
试一试{
InputStream InputStream=ContactsContract.Contacts.OpenContactsPhotoInputStream(
getActivity().getContentResolver(),
ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,新的Long(id).longValue());
如果(inputStream!=null)
photo=BitmapFactory.decodeStream(inputStream);
}捕获(例外e){
}
返回照片;
}
}
}
我觉得这可能是从联系人那里获取照片的有效方式的问题。在这里,我首先获取联系人id,然后使用联系人id查询照片。这是正确的方法吗


最后的查询不是异步工作的。要实现异步,我应该怎么做?

在您的
bindView
上,有三个主要的性能问题需要解决

  • 最严重的问题
  • 调用
    private Bitmap getPhoto
    ,这是一个SQLite操作,之后是一个磁盘加载操作。这需要几毫秒的时间,而且绝对是滞后的
    Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
    Picasso.with(getActivity()).load(uri).into(imageView);