ExpandableListView是可以展开与收拢的列表,通过下面图片展示,有个初步认识,见下图:
1、折叠的时候:
2、点击“可更新的应用(6)”,进行展开的时候:
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; } }
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
} */
}
}
}