天天看点

ExpandableListView、BaseExpandableListAdapter用法

1、折叠的时候:

ExpandableListView、BaseExpandableListAdapter用法

2、点击“可更新的应用(6)”,进行展开的时候:

ExpandableListView、BaseExpandableListAdapter用法

3、实现步骤主要分为:

1>构建ExpandableListView布局,如

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ExpandableListView
        android:id="@+id/ecpandable"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
           

2>集成BaseExpandableListAdapter,实现自己的Adapter,为此我们需要以下方法

public int getGroupCount();//所有折叠后的组个数,即与“可更新的应用(6)”同一级别的个数
public int getChildrenCount(int groupPosition);//每个组所具有的子集个数,即上图中类似“美图秀秀”等应用个数
public int getChildType(int groupPosition, int childPosition);//子集类别
public int getChildTypeCount();//子集个数
public Object getGroup(int groupPosition);//获得指定组
public Object getChild(int groupPosition, int childPosition);//获得指定组的子集
public long getGroupId(int groupPosition);//获得组ID
public long getChildId(int groupPosition, int childPosition);//获得子集ID
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent);//获得组视图(用来展现组)
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent);//获得子集视图(用来展现子集)
           

3>基本初始化

mUpdateAdapter = new ExpandableListAdapter(this);
        mUpdateAdapter.registerCallback(this);//注册回调函数
        mListView.setAdapter(mUpdateAdapter);
        mListView.setCacheColorHint(Color.TRANSPARENT);//点击时候不会变黑
        mListView.setGroupIndicator(null);//去掉左边图标
        mListView.expandGroup(ExpandableListAdapter.GROUP_UPDATE);//触发展开
        mListView.expandGroup(ExpandableListAdapter.GROUP_IGNORE);//触发展开
           

4>装数且触发刷新列表

notifyDataSetChanged();
           

4、具体实现

ExpandListViewActivity

package com.example.test.activity;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ExpandableListView;

import com.example.test.R;
import com.example.test.adapter.ExpandableListAdapter;
import com.example.test.bean.AppUpdate;
import com.example.test.common.Constants;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class ExpandListViewActivity extends BaseActivity implements ExpandableListAdapter.Callback {

    private final static String TAG = "ExpandListViewActivity";

    private ExpandableListView mListView;

    private ExpandableListAdapter mUpdateAdapter;

    private static final String JSON_UPAPPITEMS = "upappitems";

    private static final String JSON_IGNOREAPPITEMS = "ignoreappitems";

    private static final String NAME_ENTITIES = "entities";

    public List<AppUpdate> mUpdates = new ArrayList<AppUpdate>();

    public List<AppUpdate> mIgnores = new ArrayList<AppUpdate>();

    private static final int VALUE_IGNORE = 1;

    private static String PREF_IGNORE = "ignore";

    public static final int STATUS_NOT_INSTALLED = 0;

    public static final int STATUS_INSTALLED = 1;

    public static final int STATUS_INSTALLED_OLD_VERSION = 2;

    @Override
    protected int getContentLayout() {
        return R.layout.activity_expand;
    }

    @Override
    public void initGui() {
        mListView = (ExpandableListView) this.findViewById(R.id.ecpandable);
    }

    @Override
    public void initAction() {
        mListView.setEmptyView(findViewById(android.R.id.empty));
        mUpdateAdapter = new ExpandableListAdapter(this);
        mUpdateAdapter.registerCallback(this);//注册回调函数
        mListView.setAdapter(mUpdateAdapter);
        mListView.setCacheColorHint(Color.TRANSPARENT);//点击时候不会变黑
        mListView.setGroupIndicator(null);//去掉左边图标
        mListView.expandGroup(ExpandableListAdapter.GROUP_UPDATE);//触发展开
        mListView.expandGroup(ExpandableListAdapter.GROUP_IGNORE);//触发展开
        /*
        mListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {//折叠
            @Override
            public void onGroupCollapse(int groupPosition) {
                mListView.expandGroup(groupPosition);
            }
        });
        mListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {//展开
            @Override
            public void onGroupExpand(int groupPosition) {
                for (int i = 0; i < mUpdateAdapter.getGroupCount(); i++) {
                    if (groupPosition != i) {
                        mListView.collapseGroup(i);
                    }
                }
            }
        });
        */
    }

    @Override
    public void initData() {
        showData();
    }

    public void showData() {
        JSONObject jsonObj = null;
        try {
            byte[] bytes = readFromAsset(this, "preload/update.json");
            if (bytes != null) {
                jsonObj = new JSONObject(new String(bytes));
            } else {

            }
            JSONObject entities = jsonObj.optJSONObject(NAME_ENTITIES);
            if (entities != null) {
                readFromJSON(entities);
                //上次忽略更新的应用
                SharedPreferences pref = getSharedPreferences(PREF_IGNORE, 0);
                Set<String> ignoreSet = pref.getAll().keySet();
                List<AppUpdate> update = new ArrayList<AppUpdate>();
                List<AppUpdate> ignore = new ArrayList<AppUpdate>();
                if (mUpdates != null) {
                    for (AppUpdate au : mUpdates) {
                        //比较本地应用
                        //int status = getXXX(au.mPackageName, au.mVersionCode, au.mVersion);
                        //if (status != STATUS_INSTALLED_OLD_VERSION)
                        //    continue;
                        if (ignoreSet.contains(au.mPackageName)) {
                            ignore.add(au);
                        } else {
                            update.add(au);
                        }
                    }
                }
                mUpdateAdapter.setData(update, ignore);
            }
        } catch (Exception e) {
        }
    }

    public static byte[] readFromAsset(Context context, String fileName) {
        byte[] ret = null;
        InputStream instream = null;
        try {
            instream = context.getAssets().open(fileName);
            byte[] buffer = new byte[8192];
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len = -1;
            while ((len = instream.read(buffer)) >= 0)
                baos.write(buffer, 0, len);
            baos.flush();
            ret = baos.toByteArray();
            baos.close();
        } catch (IOException e) {
        } finally {
            try {
                if (instream != null)
                    instream.close();
            } catch (IOException e) {
            }
        }
        return ret;
    }

    @Override
    public void onUpdate(ExpandableListAdapter.UpdateInfoHolder updateInfo) {//更新
        Log.d(TAG, "onUpdate");
    }

    @Override
    public void onIgnore(AppUpdate item) {//忽略
        Log.d(TAG, "onIgnore");
        if (item == null || TextUtils.isEmpty(item.mPackageName))
            return;
        SharedPreferences pref = getSharedPreferences(PREF_IGNORE, 0);
        pref.edit().putInt(item.mPackageName, VALUE_IGNORE).commit();
        showData();
    }

    @Override
    public void onRemoveIgnore(AppUpdate item) {//取消忽略
        Log.d(TAG, "onRemoveIgnore");
        if (item == null || TextUtils.isEmpty(item.mPackageName))
            return;

        SharedPreferences pref = getSharedPreferences(Constants.PREF_IGNORE, 0);
        pref.edit().remove(item.mPackageName).commit();
        showData();
    }

    public void readFromJSON(JSONObject jsonObj) throws JSONException {
        mUpdates.clear();
        Object upAppItemObj = jsonObj.opt(JSON_UPAPPITEMS);
        if (upAppItemObj != null) {
            // 兼容两种更新接口数据
            if (upAppItemObj instanceof JSONArray) {
                parseUpdateArrayData(mUpdates, (JSONArray) upAppItemObj);
            } else if (upAppItemObj instanceof JSONObject) {
                int objCount = ((JSONObject) upAppItemObj).length();
                parseUpdateObjData(mUpdates, (JSONObject) upAppItemObj, objCount);
            } else {
                // Can't resolve upappitems, do nothing.
            }
        }

        mIgnores.clear();
        Object ignoreAppItemObj = jsonObj.opt(JSON_IGNOREAPPITEMS);
        if (ignoreAppItemObj != null) {
            if (ignoreAppItemObj instanceof JSONArray) {
                parseUpdateArrayData(mIgnores, (JSONArray) ignoreAppItemObj);
            } else if (ignoreAppItemObj instanceof JSONObject) {
                int objCount = ((JSONObject) ignoreAppItemObj).length();
                parseUpdateObjData(mIgnores, (JSONObject) ignoreAppItemObj, objCount);
            } else {
                // Can't resolve ignoreappitems, do nothing.
            }
        }
    }

    private void parseUpdateObjData(List<AppUpdate> outList, JSONObject jsonObj, int objCount) {
        int length = objCount;
        if (jsonObj == null || objCount <= 0)
            return;
        for (int pos = 0; pos < length; ++pos) {
            JSONObject updateObj = jsonObj.optJSONObject(String.valueOf(pos));
            if (updateObj == null)
                continue;
            try {
                AppUpdate update = new AppUpdate();
                update.readFromJSON(updateObj);
                outList.add(update);
            } catch (JSONException e) {
                continue;
            }
        }
    }

    private void parseUpdateArrayData(List<AppUpdate> outList, JSONArray jsonObj) {
        JSONArray updateArray = jsonObj;
        int length = 0;
        if (updateArray != null && (length = updateArray.length()) > 0) {
            for (int pos = 0; pos < length; ++pos) {
                JSONObject updateObj = updateArray.optJSONObject(pos);
                if (updateObj == null)
                    continue;
                try {
                    AppUpdate update = new AppUpdate();
                    update.readFromJSON(updateObj);
                    outList.add(update);
                } catch (JSONException e) {
                    continue;
                }
            }
        }
    }

    public JSONObject generateJSONObject() throws JSONException {
        JSONObject ret = new JSONObject();
        JSONArray array = new JSONArray();
        for (AppUpdate update : mUpdates) {
            if (update == null)
                continue;
            JSONObject updateObj = update.generateJSONObject();
            array.put(updateObj);
        }
        ret.put(JSON_UPAPPITEMS, array);
        array = new JSONArray();
        for (AppUpdate update : mIgnores) {
            if (update == null)
                continue;
            JSONObject updateObj = update.generateJSONObject();
            array.put(updateObj);
        }
        ret.put(JSON_IGNOREAPPITEMS, array);
        return ret;
    }
}
           
ExpandableListAdapter
      
package com.example.test.adapter;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.test.R;
import com.example.test.application.BaseApplication;
import com.example.test.bean.AppUpdate;
import com.example.test.utils.common.Utils;
import com.example.test.widget.button.DownStatusButton;
import com.example.test.widget.expandableTextView.ExpandableTextView;

import java.util.List;
import java.util.Locale;

public class ExpandableListAdapter extends BaseExpandableListAdapter {

    private final static String TAG="ExpandableListAdapter";

    public static final int GROUP_UPDATE = 0;//更新列表

    public static final int GROUP_IGNORE = 1;//忽略列表

    private static final int GROUP_COUNT = 2;

    private static final int CHILD_UPDATE = 0;

    private static final int CHILD_IGNORE = 1;

    private static final int CHILD_TYPE_COUNT = 2;

    private List<AppUpdate> mUpdates;

    private List<AppUpdate> mIgnores;

    private LayoutInflater mInflater;

    private Callback mCallback;

    private static Context context;

    private String mShowControlPackage;//本应用

    public interface Callback {

        public void onUpdate(UpdateInfoHolder updateInfo);

        public void onIgnore(AppUpdate item);

        public void onRemoveIgnore(AppUpdate item);
    }

    public ExpandableListAdapter(Context context) {
        mInflater = LayoutInflater.from(context);
        this.context = context;
    }

    public void registerCallback(Callback callback) {
        mCallback = callback;
    }

    public void setData(List<AppUpdate> updatelist, List<AppUpdate> ignorelist) {
        mUpdates = updatelist;
        mIgnores = ignorelist;
        checkmShowControlPackageExist(updatelist, ignorelist);
        notifyDataSetChanged();
    }

    private void checkmShowControlPackageExist(List<AppUpdate> updatelist, List<AppUpdate> ignorelist) {
        if(mShowControlPackage != null) {
            boolean bFind = false;
            for(AppUpdate update : updatelist) {
                if(update.mPackageName.equalsIgnoreCase(mShowControlPackage)) {
                    bFind = true;
                    break;
                }
            }
            for(AppUpdate ignore : ignorelist) {
                if(ignore.mPackageName.equalsIgnoreCase(mShowControlPackage)) {
                    bFind = true;
                    break;
                }
            }
            if(!bFind)
                mShowControlPackage = null;
        }
    }

    public List<AppUpdate> getData(int groupPosition) {
        List<AppUpdate> list = null;
        if (groupPosition == GROUP_UPDATE) {
            list = mUpdates;
        } else if (groupPosition == GROUP_IGNORE) {
            list = mIgnores;
        }
        return list;
    }

    @Override
    public int getGroupCount() {
        return GROUP_COUNT;
    }

    @Override
    public boolean isEmpty() {
        return getChildrenCount(GROUP_UPDATE) + getChildrenCount(GROUP_IGNORE) <= 0;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        if (groupPosition == GROUP_UPDATE) {
            return mUpdates == null ? 0 : mUpdates.size();
        } else if (groupPosition == GROUP_IGNORE) {
            return mIgnores == null ? 0 : mIgnores.size();
        } else {
            throw new RuntimeException();
        }
    }

    @Override
    public int getChildType(int groupPosition, int childPosition) {
        if (groupPosition == GROUP_UPDATE) {
            return CHILD_UPDATE;
        } else if (groupPosition == GROUP_IGNORE) {
            return CHILD_IGNORE;
        } else {
            throw new RuntimeException();
        }
    }

    @Override
    public int getChildTypeCount() {
        return CHILD_TYPE_COUNT;
    }

    @Override
    public Object getGroup(int groupPosition) {
        return groupPosition;
    }

    @Override
    public Object getChild(int groupPosition, int childPosition) {
        if (groupPosition == GROUP_UPDATE) {
            return mUpdates.get(childPosition);
        } else if (groupPosition == GROUP_IGNORE) {
            return mIgnores.get(childPosition);
        } else {
            throw new RuntimeException();
        }
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return groupPosition * 0x10000000 + childPosition;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        Resources res = parent.getResources();
        String formatString = null;
        if (groupPosition == GROUP_UPDATE) {
            formatString = res.getString(R.string.can_be_update);
        } else if (groupPosition == GROUP_IGNORE) {
            formatString = res.getString(R.string.already_ignored);
        } else {
            throw new RuntimeException();
        }

        int count = getChildrenCount(groupPosition);
        String title = String.format(Locale.getDefault(), formatString, count);
        convertView = buildUpdateGroupView(mInflater, groupPosition, title, isExpanded,
                convertView, parent);

        View emptyView = convertView.findViewById(R.id.empty_view);
        View contentView = convertView.findViewById(R.id.content_layout);

        if (groupPosition == GROUP_IGNORE) {
            emptyView.setVisibility(count <= 0 ? View.VISIBLE : View.GONE);
            contentView.setVisibility(count <= 0 ? View.GONE : View.VISIBLE);
        } else {
            emptyView.setVisibility(View.GONE);
            contentView.setVisibility(View.VISIBLE);
        }
        return convertView;
    }

    @Override
    public View getChildView(int groupPosition, int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {
        if (groupPosition == GROUP_UPDATE) {
            return getUpdateView(groupPosition, childPosition, isLastChild, convertView, parent);
        } else if (groupPosition == GROUP_IGNORE) {
            return getIgnoreView(groupPosition, childPosition, isLastChild, convertView, parent);
        } else {
            throw new RuntimeException();
        }
    }

    private View getUpdateView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        AppUpdate item = (AppUpdate) getChild(groupPosition, childPosition);
        convertView = buildUpdateItemView(mInflater, childPosition, item,
                item.mPackageName.equals(mShowControlPackage), convertView, parent);
        if (isLastChild) {
            convertView.findViewById(R.id.update_item_divider).setVisibility(View.GONE);
        } else {
            convertView.findViewById(R.id.update_item_divider).setVisibility(View.VISIBLE);
        }

        convertView.setOnClickListener(mOnItemClicked);
        UpdateItemViewHolder holder = (UpdateItemViewHolder) convertView.getTag();
        holder.mIgnoreButton.setOnClickListener(mOnIgnoreClicked);
        holder.mUpdateInfo.mDownButton.setOnClickListener(mOnUpdateClicked);
        return convertView;
    }

    private View getIgnoreView(final int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        final AppUpdate item = (AppUpdate) getChild(groupPosition, childPosition);
        convertView = buildIgnoreItemView(mInflater, groupPosition, item, item.mPackageName.equals(mShowControlPackage), convertView, parent);
        if (isLastChild) {
            convertView.findViewById(R.id.ignore_item_divider).setVisibility(View.GONE);
        } else {
            convertView.findViewById(R.id.ignore_item_divider).setVisibility(View.VISIBLE);
        }
        convertView.setOnClickListener(mOnItemClicked);
        IgnoreItemViewHolder holder = (IgnoreItemViewHolder) convertView.getTag();
        holder.mIgnoreInfo.mDownButton.setOnClickListener(mOnCancelIgnoreClicked);
        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }

    private View.OnClickListener mOnItemClicked = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG, "mOnItemClicked");
            Object tag = v.getTag();
            if (tag == null)
                return;

            if(tag instanceof UpdateItemViewHolder) {
                String packageName = ((UpdateItemViewHolder) tag).mPackageName;
                if (packageName.equals(mShowControlPackage)) {
                    mShowControlPackage = null;
                } else {
                    mShowControlPackage = packageName;
                }
                notifyDataSetChanged();
            } else if(tag instanceof IgnoreItemViewHolder) {
                String packageName = ((IgnoreItemViewHolder) tag).mPackageName;
                if (packageName.equals(mShowControlPackage)) {
                    mShowControlPackage = null;
                } else {
                    mShowControlPackage = packageName;
                }
                notifyDataSetChanged();
            }
        }
    };

    private View.OnClickListener mOnIgnoreClicked = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mCallback != null) {
                AppUpdate item = ((AppUpdate) v.getTag());
                mCallback.onIgnore(item);
            }
        }
    };

    private View.OnClickListener mOnUpdateClicked = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mCallback != null) {
                UpdateInfoHolder item = ((UpdateInfoHolder) v.getTag());
                mCallback.onUpdate(item);
            }
        }
    };

    private View.OnClickListener mOnCancelIgnoreClicked = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mCallback != null) {
                Log.d(TAG,"mOnCancelIgnoreClicked");
                AppUpdate item = ((AppUpdate) v.getTag());
                mCallback.onRemoveIgnore(item);
            }
        }
    };

    public static View buildUpdateGroupView(LayoutInflater inflater, int position, String title,
                                            boolean isExpanded, View convertView, ViewGroup parent) {
        UpdateGroupViewHolder holder = null;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.list_item_update_group, null);
            holder = new UpdateGroupViewHolder();
            holder.mContentLayout = convertView.findViewById(R.id.content_layout);
            holder.mEmptyLayout = convertView.findViewById(R.id.empty_view);
            holder.mTitle = (TextView) convertView.findViewById(R.id.group_title);
            convertView.setTag(holder);
        } else {
            holder = (UpdateGroupViewHolder) convertView.getTag();
        }

        holder.mTitle.setText(title);
        return convertView;
    }

    public View buildUpdateItemView(LayoutInflater inflater, int position, AppUpdate item,
                                    boolean isExpand, View convertView, ViewGroup parent) {
        UpdateItemViewHolder holder = null;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.list_item_update, null);
            holder = new UpdateItemViewHolder();
            holder.mUpdateInfo = new UpdateInfoHolder();
            holder.mUpdateInfo.mIcon = (ImageView) convertView.findViewById(R.id.icon);
            holder.mUpdateInfo.mDownButton = (DownStatusButton) convertView.findViewById(R.id.update_button);
            holder.mLabel = (TextView) convertView.findViewById(R.id.label);
            holder.mAppSize = (TextView) convertView.findViewById(R.id.text_app_size);
            holder.mNewVersion = (TextView) convertView.findViewById(R.id.new_version);
            holder.mIgnoreButton = (TextView) convertView.findViewById(R.id.ignore_button);
            holder.mUpdateView = (ExpandableTextView) convertView.findViewById(R.id.update_info_view);
            holder.mPatchSize = (TextView) convertView.findViewById(R.id.text_patch_size);
            holder.mPatchLine = (ImageView) convertView.findViewById(R.id.image_patch_line);
            convertView.setTag(holder);
        } else {
            holder = (UpdateItemViewHolder) convertView.getTag();
        }
        Resources res = parent.getResources();
        Locale locale = Locale.getDefault();
        String localFormat = res.getString(R.string.local_version);
        String newFormat = res.getString(R.string.new_version);
        holder.mUpdateInfo.mItem = item;
        Uri uri = Uri.parse("package:" + item.mPackageName);
        holder.mUpdateInfo.mIcon.setScaleType(ImageView.ScaleType.CENTER);
        holder.mUpdateInfo.mIcon.setWillNotCacheDrawing(false);
        String scheme = uri.getScheme();
        PackageManager mPackageManager = context.getPackageManager();
        if (TextUtils.isEmpty(scheme))
            return null;
        if ("package".equals(scheme)) {
            try {
                int index = uri.toString().indexOf(":") + 1;
                String packageName = uri.toString().substring(index);
                Drawable iconDrawable = mPackageManager.getApplicationIcon(packageName);
                holder.mUpdateInfo.mIcon.setScaleType(ImageView.ScaleType.FIT_CENTER);
                holder.mUpdateInfo.mIcon.setImageDrawable(iconDrawable);
            } catch (Exception e) {
            }
        }
        holder.mPackageName = item.mPackageName;
        holder.mLabel.setText(item.mLabel);
        holder.mAppSize.setText(Utils.getSizeString(item.mFileSize));
        if (item.mHasPatch) {
            holder.mPatchSize.setText(Utils.getSizeString(item.mPatchSize));
            holder.mPatchSize.setVisibility(View.VISIBLE);
            holder.mPatchLine.setVisibility(View.VISIBLE);
        } else {
            holder.mPatchSize.setVisibility(View.GONE);
            holder.mPatchLine.setVisibility(View.GONE);
        }
        String oldVersion = String.format(locale, localFormat, item.mLocalVersion);
        String newVersion = String.format(locale, newFormat, item.mVersion);
        if (!oldVersion.equalsIgnoreCase(newVersion))
            holder.mNewVersion.setText(oldVersion + " → " + newVersion);
        else {
            PackageManager pm = BaseApplication.getInstance().getContext().getPackageManager();
            try {
                PackageInfo info = pm.getPackageInfo(item.mPackageName, 0);
                int versionCode = info.versionCode;
                holder.mNewVersion.setText(oldVersion + "_" + versionCode + " → " + newVersion + "_" + item.mVersionCode);
            } catch (PackageManager.NameNotFoundException e) {
                holder.mNewVersion.setText(oldVersion + " → " + newVersion + "_" + item.mVersionCode);
            }
        }
        String strUpdateInfo = item.mUpdateInfo;
        if (TextUtils.isEmpty(strUpdateInfo)) {
            strUpdateInfo = res.getString(R.string.update_description_empty);
        }
        holder.mUpdateView.setChangeLevel(item.isImportantUpdate());
        holder.mUpdateView.setUpdateTime(item.mUpdateTime);
        holder.mIgnoreButton.setTag(item);
        Utils.scaleClickRect(holder.mIgnoreButton);
        holder.mUpdateView.setViewButton(holder.mIgnoreButton);

        if (TextUtils.isEmpty(strUpdateInfo)) {
            holder.mUpdateView.setVisibility(View.GONE);
        } else {
            holder.mUpdateView.setText(strUpdateInfo);
            holder.mUpdateView.setExpand(isExpand);
            holder.mUpdateView.setVisibility(View.VISIBLE);
        }
        return convertView;
    }

    public static View buildIgnoreItemView(LayoutInflater inflater, int position, AppUpdate item,
                                           boolean isExpand, View convertView, ViewGroup parent) {
        IgnoreItemViewHolder holder = null;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.list_item_ignore, null);
            holder = new IgnoreItemViewHolder();
            holder.mIgnoreInfo = new UpdateInfoHolder();
            holder.mIgnoreInfo.mItem = item;
            holder.mIgnoreInfo.mIcon = (ImageView) convertView.findViewById(R.id.icon);
            holder.mIgnoreInfo.mDownButton = (DownStatusButton) convertView.findViewById(R.id.update_button);
            holder.mLabel = (TextView) convertView.findViewById(R.id.label);
            holder.mAppSize = (TextView) convertView.findViewById(R.id.text_app_size);
            holder.mNewVersion = (TextView) convertView.findViewById(R.id.new_version);
            holder.mIgnoreCancelButton = (TextView) convertView.findViewById(R.id.cancel_ignore_button);
            holder.mIgnoreView = (ExpandableTextView) convertView.findViewById(R.id.ignore_info_view);
            convertView.setTag(holder);
        } else {
            holder = (IgnoreItemViewHolder) convertView.getTag();
        }
        Resources res = parent.getResources();
        Locale locale = Locale.getDefault();
        String localFormat = res.getString(R.string.local_version);
        String newFormat = res.getString(R.string.new_version);
        String descFormat = res.getString(R.string.update_description);
        if (TextUtils.isEmpty(descFormat)) {
            descFormat = res.getString(R.string.update_description_empty);
        }
        Uri uri = Uri.parse("package:" + item.mPackageName);
        holder.mIgnoreInfo.mIcon.setScaleType(ImageView.ScaleType.CENTER);
        holder.mIgnoreInfo.mIcon.setWillNotCacheDrawing(false);
        String scheme = uri.getScheme();
        PackageManager mPackageManager = context.getPackageManager();
        if (TextUtils.isEmpty(scheme))
            return null;
        if ("package".equals(scheme)) {
            try {
                int index = uri.toString().indexOf(":") + 1;
                String packageName = uri.toString().substring(index);
                Drawable iconDrawable = mPackageManager.getApplicationIcon(packageName);
                holder.mIgnoreInfo.mIcon.setScaleType(ImageView.ScaleType.FIT_CENTER);
                holder.mIgnoreInfo.mIcon.setImageDrawable(iconDrawable);
            } catch (Exception e) {
            }
        }
        holder.mPackageName = item.mPackageName;
        holder.mLabel.setText(item.mLabel);
        holder.mAppSize.setText(Utils.getSizeString(item.mFileSize));
        holder.mNewVersion.setText(String.format(locale, localFormat, item.mLocalVersion) + " → " +
                String.format(locale, newFormat, item.mVersion));
        String strUpdateInfo = item.mUpdateInfo;
        if (TextUtils.isEmpty(strUpdateInfo)) {
            strUpdateInfo = res.getString(R.string.update_description_empty);
        }
        holder.mIgnoreView.setChangeLevel(item.isImportantUpdate());
        holder.mIgnoreView.setUpdateTime(item.mUpdateTime);
        holder.mIgnoreCancelButton.setTag(item);
        holder.mIgnoreInfo.mDownButton.setTag(item);
        if (TextUtils.isEmpty(strUpdateInfo)) {
            holder.mIgnoreView.setVisibility(View.GONE);
        } else {
            holder.mIgnoreView.setText(strUpdateInfo);
            holder.mIgnoreView.setExpand(isExpand);
            holder.mIgnoreView.setVisibility(View.VISIBLE);
        }
        return convertView;
    }

    public static class UpdateGroupViewHolder {
        public View mContentLayout;
        public View mEmptyLayout;
        public TextView mTitle;
    }

    public static class UpdateInfoHolder {
        public AppUpdate mItem;
        public ImageView mIcon;
        public DownStatusButton mDownButton;
    }

    public static class UpdateItemViewHolder {
        public String mPackageName;
        public TextView mLabel;
        public TextView mAppSize;
        public TextView mNewVersion;
        public UpdateInfoHolder mUpdateInfo;
        public TextView mIgnoreButton;
        public ExpandableTextView mUpdateView;
        public TextView mPatchSize;
        public ImageView mPatchLine;
    }

    public static class IgnoreItemViewHolder {
        public String mPackageName;
        public TextView mLabel;
        public TextView mAppSize;
        public TextView mNewVersion;
        public UpdateInfoHolder mIgnoreInfo;
        public TextView mIgnoreCancelButton;
        public ExpandableTextView mIgnoreView;
    }
}
           

AppUpdate

package com.example.test.bean;

import android.text.TextUtils;

import com.example.test.data.IDataBase;

import org.json.JSONException;
import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.util.Locale;

public class AppUpdate implements IDataBase {

	/** 用于移除软件标题后无用版本号的匹配正则表达式 */
	private static final String UNUSED_INFO_REGEXP = "[vV][0-9].*[((][aA].*";
	
	private static final String JSON_PACKAGE_NAME = "packagename";

	private static final String JSON_VERSION = "version";

	private static final String JSON_VERSION_NAME = "versionname";

	private static final String JSON_SIZE = "size";

	private static final String JSON_TITLE = "title";

	private static final String JSON_UP_DATE = "upDate";

	private static final String JSON_DOWN_URL = "downUrl";

	private static final String JSON_LOCAL_VERSION = "local_version";

	private static final String JSON_UPDATE_INFO = "updateinfo";

	private static final String NAME_PKG_ID = "pkg_id";

	private static final String NAME_IS_PATCH = "isPatch";

	private static final String PATCH_SIZE = "patchSize";

	private static final String PATCH_URL = "patchUrl";
	
	/** 更新软件包名 */
	public String mPackageName;
	
	/** 更新软件名称 */
	public String mLabel;
	
	/** 版本号 */
	public int mVersionCode;
	
	/** 版本 */
	public String mVersion;
	
	/** 文件大小 */
	public long mFileSize;
	
	/** 更新时间 */
	public long mUpdateTime;
	
	/** 下载地址 */
	public String mDownloadPath;
	
	/** 本地版本 */
	public String mLocalVersion;
	
	/** 更新说明 */
	public String mUpdateInfo;
	/** 渠道ID*/
	public int mChannelId;
	
	//增量更新参数
	public boolean mHasPatch;

	public long mPatchSize;

	public String mPatchUrl;

	
	/** 标记更新的下载状态 */
	private int mTaskStatus;
	/** 标记更新的安装状态 */
	private int mInstStatus;
	
	public boolean isImportantUpdate() {
		String newVersionFirstWord = mVersion.substring(0,1);
		String oldVersionFirstWord = mLocalVersion.substring(0,1);
		return !newVersionFirstWord.equalsIgnoreCase(oldVersionFirstWord);
	}

	@Override
	public void readFromJSON(JSONObject jsonObj) throws JSONException {
		mPackageName = jsonObj.optString(JSON_PACKAGE_NAME);
		mVersionCode = jsonObj.optInt(JSON_VERSION);
		mVersion = jsonObj.optString(JSON_VERSION_NAME);
		mFileSize = jsonObj.optLong(JSON_SIZE);
		mLabel = jsonObj.optString(JSON_TITLE);
		mUpdateInfo = jsonObj.optString(JSON_UPDATE_INFO);
		mChannelId = jsonObj.optInt(NAME_PKG_ID);
		mHasPatch = jsonObj.optBoolean(NAME_IS_PATCH);
		mPatchSize = jsonObj.getLong(PATCH_SIZE);
		mPatchUrl = jsonObj.optString(PATCH_URL);
		//容错处理,防止patch包比原始包大的情况
		if(mPatchSize >mFileSize && mHasPatch) {
			mHasPatch = false;
			mPatchSize = 0;
		}
		try {
			mUpdateTime = jsonObj.getLong(JSON_UP_DATE);
		} catch (JSONException e) {
			// 接口可能出现直接传输日期字符串的方式,做一些异常处理
			mUpdateTime = tryParseTimeString(jsonObj.getString(JSON_UP_DATE));
		}
		mDownloadPath = jsonObj.optString(JSON_DOWN_URL);
		mLocalVersion = jsonObj.optString(JSON_LOCAL_VERSION);
		mLabel = filterLabelVersion(mLabel);
		if (TextUtils.isEmpty(mPackageName) || TextUtils.isEmpty(mDownloadPath))
			throw new JSONException("");
	}

	@Override
	public JSONObject generateJSONObject() throws JSONException {
		JSONObject ret = new JSONObject();
		ret.put(JSON_PACKAGE_NAME, mPackageName);
		ret.put(JSON_VERSION, mVersionCode);
		ret.put(JSON_VERSION_NAME, mVersion);
		ret.put(JSON_SIZE, mFileSize);
		ret.put(JSON_TITLE, mLabel);
		ret.put(JSON_UP_DATE, mUpdateTime);
		ret.put(JSON_DOWN_URL, mDownloadPath);
		ret.put(JSON_LOCAL_VERSION, mLocalVersion);
		ret.put(JSON_UPDATE_INFO, mUpdateInfo);
		ret.put(NAME_PKG_ID, mChannelId);
		ret.put(NAME_IS_PATCH, mHasPatch);
		ret.put(PATCH_SIZE, mPatchSize);
		ret.put(PATCH_URL, mPatchUrl);
		return ret;
	}
	
	final private long tryParseTimeString(String string) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
		try {
			return format.parse(string).getTime();
		} catch (Exception e) { }
		return 0;
	}
	
	final public static String filterLabelVersion(String label) {
		if (TextUtils.isEmpty(label))
			return "";
		return label.replaceAll(UNUSED_INFO_REGEXP, "");
	}

	@Override
	public boolean equals(Object o) {
		if (o == null || !(o instanceof AppUpdate))
			return false;
		AppUpdate another = (AppUpdate) o;
		if (mPackageName == null) {
			return another.mPackageName == null;
		} else {
			return mPackageName.equals(mPackageName);
		}
	}

	@Override
	public int hashCode() {
		return mPackageName == null ? 0 : mPackageName.hashCode();
	}

	public void setTaskStatus(int status) {
		mTaskStatus = status;
	}
	
	public int getTaskStatus() {
		return mTaskStatus;
	}

	public void setInstStatus(int status) {
		mInstStatus = status;
	}
	
	public int getInstStatus() {
		return mInstStatus;
	}
	
}
           

update.json

{
  "context": "context",
  "entities": {
    "noticeInterval": 1491377122879,
    "upappitems": [
      {
        "packagename": "com.mt.mtxx.mtxx",
        "version": 6200,
        "versionname": "3.2",
        "size": 45023969,
        "title": "美图秀秀",
        "updateinfo": "增加美颜",
        "pkg_id": 12,
        "isPatch": true,
        "patchSize": 5242880,
        "patchUrl": "http://com.mt.mtxx.mtxx/down/getPatch.do?packagename=com.mt.mtxx.mtxx&pkg_id=12",
        "downUrl": "http://com.mt.mtxx.mtxx/down/getApk.do?packagename=com.mt.mtxx.mtxx&pkg_id=12",
        "upDate": 1491377122879,
        "local_version": "1.1",
        "isPatch": true
      },
      {
        "packagename": "com.sohu.tv",
        "version": 4400000,
        "versionname": "4.4",
        "size": 8703136,
        "title": "搜狐视频HD",
        "updateinfo": "增加人民的名义反腐电视剧",
        "pkg_id": 13,
        "isPatch": true,
        "patchSize": 20971520,
        "patchUrl": "http://com.sohu.tv/down/getPatch.do?packagename=com.mt.mtxx.mtxx&pkg_id=13",
        "downUrl": "http://com.sohu.tv/down/getApk.do?packagename=com.mt.mtxx.mtxx&pkg_id=13",
        "upDate": 1491377122879,
        "local_version": "4.1",
        "isPatch": true
      },
      {
        "packagename": "com.baidu.BaiduMap.pad",
        "version": 472,
        "versionname": "2.4",
        "size": 104857600,
        "title": "百度地图",
        "updateinfo": "增加离线地图",
        "pkg_id": 14,
        "isPatch": true,
        "patchSize": 209715,
        "patchUrl": "http://com.baidu.BaiduMap.pad/down/getPatch.do?packagename=com.mt.mtxx.mtxx&pkg_id=14",
        "downUrl": "http://com.baidu.BaiduMap.pad/down/getApk.do?packagename=com.mt.mtxx.mtxx&pkg_id=14",
        "upDate": 1491377122879,
        "local_version": "1.1",
        "isPatch": true
      },
      {
        "packagename": "com.sina.weibotab",
        "version": 26916,
        "versionname": "3.5.9",
        "size": 104857600,
        "title": "微博HD",
        "updateinfo": "增加直播",
        "pkg_id": 15,
        "isPatch": true,
        "patchSize": 20971520,
        "patchUrl": "http://com.baidu.BaiduMap.pad/down/getPatch.do?packagename=com.sina.weibotab&pkg_id=15",
        "downUrl": "http://com.baidu.BaiduMap.pad/down/getApk.do?packagename=com.sina.weibotab&pkg_id=15",
        "upDate": 1491377122879,
        "local_version": "1.1",
        "isPatch": true
      },
      {
        "packagename": "com.baidu.netdisk_ss",
        "version": 220,
        "versionname": "1.1",
        "size": 104857600,
        "title": "百度云",
        "updateinfo": "增加3TB空间",
        "pkg_id": 16,
        "isPatch": true,
        "patchSize": 20971520,
        "patchUrl": "http://com.baidu.BaiduMap.pad/down/getPatch.do?packagename=com.baidu.netdisk_ss&pkg_id=16",
        "downUrl": "http://com.baidu.BaiduMap.pad/down/getApk.do?packagename=com.baidu.netdisk_ss&pkg_id=16",
        "upDate": 1491377122879,
        "local_version": "1.1",
        "isPatch": true
      },
      {
        "packagename": "com.taobao.apad",
        "version": 26,
        "versionname": "2.6",
        "size": 10485760,
        "title": "淘宝HD",
        "updateinfo": "双11",
        "pkg_id": 17,
        "isPatch": true,
        "patchSize": 20971520,
        "patchUrl": "http://com.baidu.BaiduMap.pad/down/getPatch.do?packagename=com.taobao.apad&pkg_id=17",
        "downUrl": "http://com.baidu.BaiduMap.pad/down/getApk.do?packagename=com.taobao.apad&pkg_id=17",
        "upDate": 1491377122879,
        "local_version": "1.1",
        "isPatch": true
      }
    ],
    "ignoreappitems": {
      /*
      "0": {
        "packagename": "com.taobao.apad",
        "version": 26,
        "versionname": "2.6",
        "size": 10485760,
        "title": "淘宝HD",
        "updateinfo": "双11",
        "pkg_id": 17,
        "isPatch": true,
        "patchSize": 20971520,
        "patchUrl": "http://com.baidu.BaiduMap.pad/down/getPatch.do?packagename=com.taobao.apad&pkg_id=17",
        "downUrl": "http://com.baidu.BaiduMap.pad/down/getApk.do?packagename=com.taobao.apad&pkg_id=17",
        "upDate": 1491377122879,
        "local_version": "1.1",
        "isPatch": true
      }    */
    }
  }
}