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