您的位置:首页 > 移动开发 > Android开发

android ListView 动态分页加载数据

2017-06-17 17:50 423 查看
参考文章:

http://blog.csdn.net/zimo2013/article/details/10263339
http://blog.csdn.net/zimo2013/article/details/12253301
 用ListView显示数据时,列表中数据量大时,加载和处理时间会明显变长,如果等到把所有数据都处理加载完成再显示出来,那程序的UI就非常糟糕了,很可能会随数据量的变大而变慢,这样的界面很不友好,我们无法接受。

 废话说完了,那怎么解决这个的问题呢?

 动态加载,分页加载。我不能在UI线程中做大量的读取、处理数据的动作,而是另开一个线程来做这件事。但是这样并不能保证显示及时,因为数据大时,时间仍会很长,怎么办,那我先处理一部分,先显示出来它们,后台再继续处理后面的数据,处理一部分,加载一部分。

 这就要用到Adapter和loader 类。

static class AppsListItem{
public Drawable icon = null;
public String appLabel = "";
public String summary = "";
public String packageName = "";
public int uid = -1;
public int permCount = 0;
public String key = "";

}

public static class AppListAdapter extends BaseAdapter {
Activity mActivity;
LayoutInflater mLayoutInflater;
PackageManager mPackageManager;
List<AppsListItem> mAppList;

public AppListAdapter(Activity activity){
mActivity = activity;
mLayoutInflater = activity.getLayoutInflater();
mPackageManager = activity.getPackageManager();
mAppList = new ArrayList<AppsListItem>();
}

@Override
public int getCount() {
return (mAppList == null)? 0 : mAppList.size();
}

@Override
public Object getItem(int position) {
return mAppList.get(position);
}

public Object getItem(String packageName){
for(AppsListItem appInfo : mAppList){
if(appInfo.packageName.equals(packageName)){
return appInfo;
}
}
return null;
}

@Override
public long getItemId(int position) {
return position;
}

class ViewHolder{
ImageView appIcon;
TextView appName;
TextView summary;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if(convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.permission_preference_layout2, parent, false);
viewHolder = new ViewHolder();
viewHolder.appIcon = ((ImageView) convertView.findViewById(R.id.appIcon));
viewHolder.appName = ((TextView) convertView.findViewById(R.id.appName));
viewHolder.summary = ((TextView) convertView.findViewById(R.id.summary));
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
final AppsListItem appInfo = mAppList.get(position);
viewHolder.appIcon.setImageDrawable(appInfo.icon);
viewHolder.appName.setText(appInfo.appLabel);
viewHolder.summary.setText(appInfo.summary);

return convertView;
}

public void setData(List<AppsListItem> selectedAppList) {
mAppList.clear();

if (selectedAppList != null) {
Log.w(TAG,"APP list size "+selectedAppList.size());
mAppList = selectedAppList;
}
notifyDataSetChanged();
}

public void addData(List<AppsListItem> selectedAppList) {

if (selectedAppList != null) {
Log.w(TAG,"APP list size "+selectedAppList.size());
mAppList.addAll(selectedAppList);
}
notifyDataSetChanged();
}

public void removeItem(String packageName){
AppsListItem item = (AppsListItem)getItem(packageName);
if(item != null){
mAppList.remove(item);
notifyDataSetChanged();
}
}

public void removeItem(int position){
if(position < mAppList.size()){
mAppList.remove(position);
notifyDataSetChanged();
}
}

public void addData(AppsListItem item) {
if (item != null) {
Log.w(LISTTAG,"add package "+item.packageName+" Label: "+item.appLabel);
mAppList.add(item);
}
notifyDataSetChanged();
}

}
怎么用这个Adapter 呢,

 
onStart(){
...
listview.setAdapter(mAdapter); listview.setSelectionFromTop(mSaveIndex, mtop); listview.setOnScrollChangeListener(new View.OnScrollChangeListener() { @Override public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { //mAdapter.notifyDataSetChanged(); } }); listview.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mSaveIndex = listview.getFirstVisiblePosition(); View v = listview.getChildAt(0); mtop = (v == null) ? 0 : (v.getTop() - listview.getPaddingTop()); AppsListItem appinfo = (AppsListItem)mAdapter.getItem(position); if(appinfo != null){ final String mPackageName = appinfo.packageName; final int mUid = appinfo.uid; int permCnt = appinfo.permCount; Intent sendIntent = new Intent(); sendIntent.setAction("android.intent.action.MANAGE_APP_PERMISSIONS"); sendIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName); sendIntent.putExtra(Intent.EXTRA_UID, mUid); sendIntent.putExtra("hideInfoButton", true); startActivity(sendIntent); } } });
}



Adapter 需要loader 类来给它提供数据,它才给使listView 显示出来。

所以下面是loader 类,这个类是在后台读取并处理数据,处理完成一部分,给Adapter 来显示。但是分步处理这个过程需要借助

LoaderManager的。
/**
* A custom Loader that loads all of the installed applications.
*/
public static class AppListLoader extends AsyncTaskLoader<List<AppsListItem>> {
private int mCount = 0;
private static int mOldCount = 0;
private static int mSize = 0;
private List<AppsListItem> items = null;
private static List<ApplicationInfo> apps = new ArrayList<>();
Boolean second = false;
String SHAREDPREFERENCE_INSTALLED_PERMISSION_INFO = "PermissionInfos";
public AppListLoader(Context context,int count) {
super(context);
mCount = count;
Log.w(LISTTAG,"mCount "+mCount+" mOldCount "+mOldCount);
if(items == null) {
items = new ArrayList<AppsListItem>();
}
//You Should confirm FIRSTLOAD (11) num diff from others (5)
if(mCount ==FIRSTLOAD ) {
mOldCount = 0;
}
}

@Override
public List<AppsListItem> loadInBackground() {
Log.w(LISTTAG,"===============loadInBackground =================");
return buildList();
}

@Override
protected void onStartLoading() {
Log.w(LISTTAG,"===============onStartLoading =================");
forceLoad();
}

public List<AppsListItem> buildList() {
int permcount = 0;
ApplicationInfo appInfo;
//Context context = getContext();
PackageManager pm = mContext.getPackageManager();
int index = 0;
CtaUtils mCtaUtils = new CtaUtils(mContext);

if(apps.size()==0 ) {
apps = pm.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES);//Utils.getAllInstalledApplications(context);
}

mSize = apps.size();
//Log.w(LISTTAG,"mCount "+mCount+" mOldCount "+mOldCount+" mSize "+mSize);
SharedPreferences permissionInfos = mContext.getSharedPreferences(SHAREDPREFERENCE_INSTALLED_PERMISSION_INFO, 0);
SharedPreferences.Editor editor = permissionInfos.edit();
for(int i=0;i<mSize;i++){
index = mOldCount+i;
if(index <mSize) {
appInfo = apps.get(index);
if(shouldSkipFirst(pm,appInfo)){
//Log.w(LISTTAG, "shouldSkipFirst I " + i+" index" +index);
continue;
}

String preKey = appInfo.packageName + "|" + appInfo.uid;
permcount = permissionInfos.getInt(preKey, -1);
if (permcount < 0) {
//Log.w(LISTTAG, "getCount I " + i+" index "+index);
permcount = getPermissionCountInner(appInfo.packageName);
permcount = permcount + mCtaUtils.getCTARecords(appInfo.uid, appInfo.packageName);
editor.putInt(preKey, permcount);
editor.commit();
}

if (shouldSkip( permcount)) {
//Log.w(LISTTAG, "shouldSkip I " + i+" index" +index);
continue;
}

AppsListItem item = new AppsListItem();
item.appLabel = appInfo.loadLabel(pm).toString();
item.packageName = appInfo.packageName;
item.uid = appInfo.uid;
item.icon = appInfo.loadIcon(pm);
item.permCount = permcount;
item.summary = "" + permcount + mContext.getResources().getString(R.string.permission_count);
item.key = appInfo.packageName + "|" + appInfo.uid;
if (item.icon == null) {
item.icon = mContext.getResources().getDrawable(android.R.drawable.sym_def_app_icon);
}

items.add(item);
mCount--;
if(mCount==0)
break;

}else{
Log.e(LISTTAG, "Out of index! mOldCount " + mOldCount+" i "+i+" mSize "+mSize);
loadcomplete = true;
apps.clear();
break;
}
}
//Log.w(LISTTAG,"index "+index+" mCount "+mCount);
mOldCount = (index+1);

/*            try {
Collections.sort(items, APP_COMPARATOR);
}
catch (Exception e) {
}*/

return items;
}

private  int getPermissionCountInner(String packageName ){
int cnt = 0;
mPermSet.clear();
PackageInfo mPackageInfo = getPackageInfo(getContext(), packageName);

if(mPackageInfo ==null || mPackageInfo.requestedPermissions == null) {
return cnt;
}
for (String requestedPerm : mPackageInfo.requestedPermissions) {
//Log.w(TAG,"requestedPerm "+requestedPerm);
PermissionInfo permInfo = null;
try {
permInfo = mContext.getPackageManager().getPermissionInfo(requestedPerm, 0);
} catch (PackageManager.NameNotFoundException e) {
//Log.w(TAG, "NameNotFoundException "+e.getLocalizedMessage());
}

if (permInfo != null && permInfo.group != null) {
mPermSet.add(permInfo.group);
}
}

for(String groupName : mPermSet){
switch(groupName){
case PERMISSION_CALENDER_GROUP_NAME:
case PERMISSION_STORAGE_GROUP_NAME:
case PERMISSION_BODY_SENSORS_GROUP_NAME:
case PERMISSION_SMS_GROUP_NAME:
case PERMISSION_CONTACTS_GROUP_NAME:
case PERMISSION_PHONE_GROUP_NAME:
case PERMISSION_CAMERA_GROUP_NAME:
case PERMISSION_MICROPHONE_GROUP_NAME:
case PERMISSION_LOCATION_GROUP_NAME:
cnt++;
break;
}
}

return cnt;
}

/*        public static final Comparator<AppsListItem> APP_COMPARATOR = new Comparator<AppsListItem>() {
@Override
public int compare(AppsListItem item1, AppsListItem item2) {
String temp = "" + item2.switchState;
int res = temp.compareTo("" + item1.switchState);
if(res == 0){
if(item2.suggestOpenText.compareTo(item1.suggestOpenText) == 0) {
res = 0;
}else if(item2.suggestOpenText.compareTo(item1.suggestOpenText) > 0){
res = 1;
}else{
res = -1;
}
}
return res;
}
};*/

}

所以我们需要实现LoaderManager 的几个callback: onCreateLoader, onLoadFinished, onLoaderReset
在这几个callback中来把loader


public class MyActivity extends FrameFrgment  implements
LoaderManager.LoaderCallbacks<List<MyActivity.AppsListItem>> {

onCreate{
...
 mAdapter= new AppListAdapter(getActivity());
Bundle args = new Bundle();
args.putInt(loadcount,FIRSTLOAD);
getLoaderManager().initLoader(0, args, this);

...}
...
private void restartLoader(){
    Bundle args = new Bundle();

    args.putInt("count",LOADNUM);
    getLoaderManager().restartLoader(0,args,this);
    Log.w(TAG,"===============onLoaderReset =================");
}

@Override
public Loader<List<AppsListItem>> onCreateLoader(int id, Bundle args) {
    int count = 0;
    if(args != null) {
        count = args.getInt(loadcount, 10);
    }
    mAppListLoader = new AppListLoader(getActivity(),count);
    return mAppListLoader;
}

@Override
public void onLoadFinished(Loader<List<AppsListItem>> loader, List<AppsListItem> data) {
    try {
        if(mAdapter.getCount()==0) {
            mAdapter.setData(data);
            
            if(!loadcomplete) {
                //You Should confirm FIRSTLOAD (11) num diff from others (5)
                restartLoader();
            }
        }
        else {
            mAdapter.addData(data);
            
            if(!loadcomplete) {
                //You Should confirm FIRSTLOAD (11) num diff from others (5)
                restartLoader();
            }
        }
        setLoading(false,true);
    }catch (Exception err){
        Log.d(LISTTAG, "AppAutoStartList-->onLoadFinished", err);
    }
}

@Override
public void onLoaderReset(Loader<List<AppsListItem>> loader) {
    // Clear the data in the adapter.
    //mAdapter.setData(null);
}


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android app 数据 listview