一、原应用相关模块简介
1,入口:主界面-----游戏百科-----装备。
2,装备物品主界面中,列表选择物品类型,进入指定物品类型GridView,GridView点击某一项进入指定物品的物品详情界面。物品详情界面主要内容有:物品名称、物品价格、物品缩略图、物品属性、合成该物品所需物品,该物品可合成的物品。
二、功能分析
1,物品分类页面是一个ListView且分类是固定的;分类下装备列表是一个GridView,一共四列,每个物品包含一个图片和一个图片名称;物品详情界面包含一个ImageView,几个TextView和两个HorizontalScrollView,两个HorizontalScrollView中分别包含当前物品的合成所需和可合成物品的图标,图标点击后可进入到响应物品的物品详情界面。
2,获取某一物品分类下的所有物品的简要信息,使用 fiddler 抓包发现,访问请求格式为 http://lolbox.duowan.com/phone/apiZBItemList.php?tag=fumo ,其中tag参数的值代表物品分类,其返回值是一个Json,格式为
[{"id":3250,"text":"\u72c2\u6218\u58eb\u80eb\u7532\u2014\u5bb6\u56ed\u536b\u58eb"},{"id":3251,"text":"\u72c2\u6218\u58eb\u80eb\u7532\u2014\u7edf\u5e05"},{"id":3252,"text":"\u72c2\u6218\u58eb\u80eb\u7532\u2014\u55a7\u54d7"},{"id":3253,"text":"\u72c2\u6218\u58eb\u80eb\u7532\u2014\u5931\u771f"},{"id":3254,"text":"\u72c2\u6218\u58eb\u80eb\u7532\u2014\u6b22\u6b23"},{"id":3255,"text":"\u6cd5\u5e08\u4e4b\u9774\u2014\u5bb6\u56ed\u536b\u58eb"},{"id":3256,"text":"\u6cd5\u5e08\u4e4b\u9774\u2014\u7edf\u5e05"},{"id":3257,"text":"\u6cd5\u5e08\u4e4b\u9774\u2014\u55a7\u54d7"},{"id":3258,"text":"\u6cd5\u5e08\u4e4b\u9774\u2014\u5931\u771f"},{"id":3259,"text":"\u6cd5\u5e08\u4e4b\u9774\u2014\u6b22\u6b23"},{"id":3260,"text":"\u5fcd\u8005\u8db3\u5177\u2014\u5bb6\u56ed\u536b\u58eb"},{"id":3261,"text":"\u5fcd\u8005\u8db3\u5177\u2014\u7edf\u5e05"},{"id":3262,"text":"\u5fcd\u8005\u8db3\u5177\u2014\u55a7\u54d7"},{"id":3263,"text":"\u5fcd\u8005\u8db3\u5177\u2014\u5931\u771f"},{"id":3264,"text":"\u5fcd\u8005\u8db3\u5177\u2014\u6b22\u6b23"},{"id":3265,"text":"\u6c34\u94f6\u4e4b\u9774\u2014\u5bb6\u56ed\u536b\u58eb"},{"id":3266,"text":"\u6c34\u94f6\u4e4b\u9774\u2014\u7edf\u5e05"},{"id":3267,"text":"\u6c34\u94f6\u4e4b\u9774\u2014\u55a7\u54d7"},{"id":3268,"text":"\u6c34\u94f6\u4e4b\u9774\u2014\u5931\u771f"},{"id":3269,"text":"\u6c34\u94f6\u4e4b\u9774\u2014\u6b22\u6b23"},{"id":3270,"text":"\u75be\u884c\u4e4b\u9774\u2014\u5bb6\u56ed\u536b\u58eb"},{"id":3271,"text":"\u75be\u884c\u4e4b\u9774\u2014\u7edf\u5e05"},{"id":3272,"text":"\u75be\u884c\u4e4b\u9774\u2014\u55a7\u54d7"},{"id":3273,"text":"\u75be\u884c\u4e4b\u9774\u2014\u5931\u771f"},{"id":3274,"text":"\u75be\u884c\u4e4b\u9774\u2014\u6b22\u6b23"},{"id":3275,"text":"\u660e\u6717\u4e4b\u9774\u2014\u5bb6\u56ed\u536b\u58eb"},{"id":3276,"text":"\u660e\u6717\u4e4b\u9774\u2014\u7edf\u5e05"},{"id":3277,"text":"\u660e\u6717\u4e4b\u9774\u2014\u55a7\u54d7"},{"id":3278,"text":"\u660e\u6717\u4e4b\u9774\u2014\u5931\u771f"},{"id":3279,"text":"\u660e\u6717\u4e4b\u9774\u2014\u6b22\u6b23"},{"id":3280,"text":"\u8f7b\u7075\u4e4b\u9774\u2014\u5bb6\u56ed\u536b\u58eb"},{"id":3281,"text":"\u8f7b\u7075\u4e4b\u9774\u2014\u7edf\u5e05"},{"id":3282,"text":"\u8f7b\u7075\u4e4b\u9774\u2014\u55a7\u54d7"},{"id":3283,"text":"\u8f7b\u7075\u4e4b\u9774\u2014\u5931\u771f"},{"id":3284,"text":"\u8f7b\u7075\u4e4b\u9774\u2014\u6b22\u6b23"}]
结果只包含物品ID和物品名称,继续查看抓包信息可知, 由物品id取物品缩略图的 请求格式为 http://img.lolbox.duowan.com/zb/3250_64x64.png ,最后一部分下划线前是物品id,下划线后是要取的图片的大小。至此,获取指定分类的物品列表的功能所需条件已经完备。
3,获取某一物品的详细信息的请求格式为 http://lolbox.duowan.com/phone/apiItemDetail.php?id=3093,其中id参数的值代表物品的ID,请求结果是Json,格式为
{"id":"3093","name":"\u8d2a\u5a6a\u4e4b\u5203","description":"+10%\u66b4\u51fb\u51e0\u7387\uff0c\u552f\u4e00\u88ab\u52a8\u2014\u8d2a\u8d22\uff1a\u6bcf10\u79d2\u83b7\u5f97+3\u679a\u91d1\u5e01\u3002\u552f\u4e00\u88ab\u52a8\u2014\u8d2a\u5a6a\uff1a\u6bcf\u6b21\u51fb\u6740\u5355\u4f4d\u65f6\u989d\u5916\u83b7\u5f972\u679a\u91d1\u5e01\u3002\u53ef\u4ee5\u4e0e\u5176\u5b83\u91d1\u5e01\u6536\u5165\u578b\u88c5\u5907\u5171\u5b58","price":400,"allPrice":800,"sellPrice":320,"tags":" ","extAttrs":{"FlatCritChanceMod":0.1},"need":"1051","compose":"3087,3142","extDesc":"\u552f\u4e00\u88ab\u52a8\u2014\u8d2a\u8d22\uff1a\u6bcf10\u79d2\u83b7\u5f97+3\u679a\u91d1\u5e01\u3002\u552f\u4e00\u88ab\u52a8\u2014\u8d2a\u5a6a\uff1a\u6bcf\u6b21\u51fb\u6740\u5355\u4f4d\u65f6\u989d\u5916\u83b7\u5f972\u679a\u91d1\u5e01\u3002\u53ef\u4ee5\u4e0e\u5176\u5b83\u91d1\u5e01\u6536\u5165\u578b\u88c5\u5907\u5171\u5b58\u3002"}
结果中包含了当前物品 的ID、名称、价格、属性、合成所需物品的ID、可合成物品的ID。依据这些属性再结合前面根据ID获取物品图片的方式,即可把物品详情界面中的元素完全展示出来。
三、功能实现
1,几个工具类
/**
* 路径工具
* @author yangsheng
* @date 2014年12月30日
*/
public class URLUtil {
/**
* 取某分类的装备列表Json的请求URL
* @param type
* @return
*/
public static final String getURL_ZBLst(EnumZBType type){
return String.format("http://lolbox.duowan.com/phone/apiZBItemList.php?tag=%s", type.toString());
}
/**
* 取装备图片的请求URL
* @param zbId 装备id
* @param dpi 图片分辨率
* @return
*/
public static final String getURL_ZBImg(int zbId, EnumDPI dpi){
return String.format("http://img.lolbox.duowan.com/zb/%s_%s.png", zbId, dpi.toDPIString());
}
/**
* 取装备详细信息Json的请求URL
* @param zbId
* @return
*/
public static final String getURL_ZBDetail(int zbId){
return String.format("http://lolbox.duowan.com/phone/apiItemDetail.php?id=%s", zbId);
}
}
将网络请求操作统一封装在一个管理器中,方便统一管理
/**
* 全局的网络请求管理器
* @author warren
* @date 2014年12月30日
*/
public class AppNetManager {
private static AppNetManager netManager;
private LruCache cache = new LruCache(1000);
/**
* 线程安全地取唯一实例
* @return
*/
public static AppNetManager getInstance(){
if(netManager == null){
synchronized (AppNetManager.class) {
if(netManager == null){
netManager = new AppNetManager();
}
}
}
return netManager;
}
private AppNetManager(){
}
/**
* 异步请求指定URL,同步回调
* @param strUrl
* @param listener
*/
public void get(final String strUrl, final IListener listener){
String strHistory = cache.get(strUrl);
if(strHistory != null){
listener.onCall(strHistory);
return;
}
AsyncHttpClient httpClient = new AsyncHttpClient();
httpClient.get(strUrl, new AsyncHttpResponseHandler(){
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
super.onSuccess(arg0, arg1, arg2);
try {
String strResult = new String(arg2, "UTF-8");
cache.put(strUrl, strResult);
listener.onCall(strResult);
} catch (UnsupportedEncodingException e) {
LogTool.exception(e);
listener.onCall(null);
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) {
super.onFailure(arg0, arg1, arg2, arg3);
listener.onCall(null);
}
});
}
/**
* Json解析管理器
* @author warren
* @date 2014年12月31日
*/
public class AppJsonParserManager {
private static AppJsonParserManager jpm;
public static AppJsonParserManager getInstance() {
if (jpm == null) {
synchronized (AppJsonParserManager.class) {
if (jpm == null) {
jpm = new AppJsonParserManager();
}
}
}
return jpm;
}
private AppJsonParserManager() {
}
/**
* 异步解析Json,同步回调。解析成功则回调方法中的参数是解析结果,否则是 null
* @param strJson
* @param cls
* @param listener
*/
public void parse(final String strJson, final Class cls, final IListener listener) {
new AsyncTaskParser(listener, cls).execute(strJson);
}
/**
* 异步解析列表Json,同步回调。解析成功则回调方法中的参数是解析结果,否则是 null。
* @param strJson
* @param cls
* @param listener
*/
public void parseList(final String strJson, final Class cls,
final IListener> listener) {
new AsyncTaskParserList(cls, listener).execute(strJson);
}
/**
* 异步解析列表Json,同步回调
* @author warren
* @date 2014年12月31日
* @param
*/
class AsyncTaskParserList extends AsyncTask> {
private Class cls;
private IListener> listener;
public AsyncTaskParserList(Class cls, IListener> listener) {
this.listener = listener;
this.cls = cls;
}
@Override
protected List doInBackground(String... params) {
StringReader sr = new StringReader(params[0]);
List lst = new ArrayList();
try {
sr.reset();
// 解析成List时,无法直接解析成指定类型的列表,所以需要把解析得到的List>每一项单独再转成指定类型的对象。
JsonFactory factory = new ObjectMapper().getJsonFactory();
JsonParser jpar = factory.createJsonParser(sr);
List> mapLst = jpar.readValueAs(List.class);
for (HashMap map : mapLst) {
// 先将Map转换为Json字符串,再把Json字符串重新转换为指定类型的对象。
StringWriter sw = new StringWriter();
factory.createJsonGenerator(sw).writeObject(map);
T t = factory.createJsonParser(sw.toString()).readValueAs(cls);
lst.add(t);
sw.close();
}
} catch (Exception e) {
LogTool.exception(e);
}
sr.close();
return lst;
}
@Override
protected void onPostExecute(List result) {
super.onPostExecute(result);
listener.onCall(result);
}
}
/**
* 异步解析Json,同步回调
* @author warren
* @date 2014年12月31日
* @param
*/
class AsyncTaskParser extends AsyncTask {
private IListener listener;;
private Class cls;
public AsyncTaskParser(IListener listener, Class cls) {
this.listener = listener;
this.cls = cls;
}
@Override
protected T doInBackground(String... params) {
StringReader sr = new StringReader(params[0]);
T obj = null;
try {
JsonParser jpar = new ObjectMapper().getJsonFactory().createJsonParser(sr);
obj = jpar.readValueAs(cls);
} catch (Exception e) {
LogTool.exception(e);
}
sr.close();
return obj;
}
@Override
protected void onPostExecute(T result) {
super.onPostExecute(result);
listener.onCall(result);
}
}
/**
* 通用的GridView的Adapter,支持 {@link SimpleTool} 和 {@link SimpleNetTool}列表的显示
* @author yangsheng
* @date 2014年12月31日
*/
public class BaseGridAdapter extends BaseAdapter {
private LayoutInflater inflater;
private List lstTools;
private List lstNetTools;
private ImageLoader imgLoader;
private DisplayImageOptions options;
private int numColumn = 3;
public BaseGridAdapter(LayoutInflater inflater) {
this.inflater = inflater;
}
public void setLstTools(List lstTools) {
this.lstTools = lstTools;
}
public void setLstNetTools(List lstNetTools, ImageLoader imgLoader, DisplayImageOptions options) {
this.lstNetTools = lstNetTools;
this.imgLoader = imgLoader;
this.options = options;
}
/**
* @return the numColumn
*/
public int getNumColumn() {
return numColumn;
}
/**
* @param numColumn the numColumn to set
*/
public void setNumColumn(int numColumn) {
this.numColumn = numColumn;
}
@Override
public int getCount() {
return lstTools != null ? lstTools.size() : (lstNetTools != null ? lstNetTools.size() : 0);
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.griditem, parent, false);
holder = new ViewHolder();
holder.img = (ImageView) convertView.findViewById(R.id.img);
holder.tv = (TextView) convertView.findViewById(R.id.tv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// 优先显示 lstTools,如果 lstTools 为设置,则显示 lstNetTools
if (lstTools != null) {
holder.img.setImageResource(lstTools.get(position).getImgResId());
holder.tv.setText(lstTools.get(position).getTxtResId());
} else {
imgLoader.displayImage(lstNetTools.get(position).getStrImgUrl(), holder.img, options);
holder.tv.setText(lstNetTools.get(position).getStrText());
}
AbsListView.LayoutParams param = new AbsListView.LayoutParams(
parent.getWidth() / numColumn, android.view.ViewGroup.LayoutParams.MATCH_PARENT);
convertView.setLayoutParams(param);
return convertView;
}
class ViewHolder {
ImageView img;
TextView tv;
}
}
物品分类界面
/**
* 物品分类
* @author warren
* @date 2014年12月31日
*/
public class MaterialTypesActivity extends Activity {
private ImageView mImgLeft;
private ImageView mImgRight;
private TextView mTvTitle;
private ListView mLvLst;
private String[] mArrTypes = EnumZBType.getStringTypeArray();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_baike);
initCtrl();
}
private void initCtrl() {
mImgLeft = (ImageView) findViewById(R.id.img_title_left);
mImgRight = (ImageView) findViewById(R.id.img_title_right);
mTvTitle = (TextView) findViewById(R.id.tv_title);
mImgLeft.setImageResource(R.drawable.lolbox_titleview_return_default);
mImgRight.setVisibility(View.GONE);
mTvTitle.setText("物品分类");
mLvLst = (ListView) findViewById(R.id.lv_types);
AdapterList adapter = new AdapterList(LayoutInflater.from(this), mArrTypes);
mLvLst.setAdapter(adapter);
mLvLst.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
openNextActivity(position);
}
});
mImgLeft.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
/**
* 打开物品列表Activity
* @param position
*/
private void openNextActivity(int position) {
Intent it = new Intent(this, MaterialGridWithTypeActivity.class);
it.putExtra(MaterialGridWithTypeActivity.EXTRA_ZBTYPE, mArrTypes[position]);
startActivity(it);
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
}
class AdapterList extends BaseAdapter {
private LayoutInflater mInflater;
private String[] mArrTypes;
public AdapterList(LayoutInflater inflater, String[] arrType) {
this.mInflater = inflater;
this.mArrTypes = arrType;
}
@Override
public int getCount() {
return mArrTypes.length;
}
@Override
public Object getItem(int position) {
return mArrTypes[position];
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.activity_baike_listitem, parent, false);
holder = new ViewHolder();
holder.img = (ImageView) convertView.findViewById(R.id.img);
holder.tv = (TextView) convertView.findViewById(R.id.tv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.img.setVisibility(View.GONE);
holder.tv.setText(mArrTypes[position]);
return convertView;
}
class ViewHolder {
public ImageView img;
public TextView tv;
}
}
}
特定分类下的物品列表
/**
* 特定分类下的物品列表
* @author warren
* @date 2014年12月31日
*/
public class MaterialGridWithTypeActivity extends Activity {
public static final String EXTRA_ZBTYPE = "EXTRA_ZBTYPE";
private ImageView mImgLeft;
private ImageView mImgRight;
private TextView mTvTitle;
private GridView mGv;
private String mStrTitle;
private EnumZBType mEnumType;
private BaseGridAdapter mAdapter;
private List mLstMs;
private List mLstSnt;
private DisplayImageOptions mDisPlayOption;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grid);
String strType = getIntent().getStringExtra(EXTRA_ZBTYPE);
if (StringUtils.isNullOrZero(strType)) {
mStrTitle = "全部装备";
mEnumType = EnumZBType.all;
} else {
mStrTitle = strType;
mEnumType = EnumZBType.getZbType(StringUtils.getIndex(EnumZBType.getStringTypeArray(),
strType));
}
initImgOption();
initCtrl();
}
private void initImgOption() {
// 这里无需设置这么多,一般使用ImageLoader的默认DisplayImageOptions就可以满足需求
Options opt = new Options();
opt.inInputShareable = true;
opt.inPurgeable = true;
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inSampleSize = 1;
mDisPlayOption = new DisplayImageOptions.Builder()
.considerExifParams(true)
.bitmapConfig(Config.RGB_565)
.decodingOptions(opt)
.displayer(new BitmapDisplayer() {
@Override
public void display(Bitmap arg0, ImageAware arg1, LoadedFrom arg2) {
// 由于请求的图片较小,在分辨率较大的设备上显示不美观。这里在显示前先放大到两倍,再显示。
// 放大到两倍后,经检查大部分手机分辨率都能较好地展示,而放大后的图片对某一分辨率来说太大时,
// 可通过设置ImageView的ScaleType来将自动将图片缩小。
Matrix matrix = new Matrix();
matrix.postScale(2, 2);
Bitmap bitResize = Bitmap.createBitmap(arg0, 0, 0, arg0.getWidth(),
arg0.getHeight(), matrix, true);
arg1.setImageBitmap(bitResize);
}
}).cacheInMemory(true).showImageOnLoading(R.drawable.dl_loading_img)
.imageScaleType(ImageScaleType.IN_SAMPLE_INT).build();
}
private void initCtrl() {
mImgLeft = (ImageView) findViewById(R.id.img_title_left);
mImgRight = (ImageView) findViewById(R.id.img_title_right);
mTvTitle = (TextView) findViewById(R.id.tv_title);
mImgLeft.setImageResource(R.drawable.lolbox_titleview_return_default);
mImgRight.setVisibility(View.GONE);
mTvTitle.setText(mStrTitle);
mImgLeft.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
mGv = (GridView) findViewById(R.id.grid);
mGv.setNumColumns(4);
mAdapter = new BaseGridAdapter(LayoutInflater.from(this));
GridParams params = GridParams.createNormal();
params.imgFillRootWidth = true;
mAdapter.setNumColumn(4);
mGv.setAdapter(mAdapter);
// 请求服务器,查询某一类型的物品列表
AppContext.getApp().getNetManager()
.get(URLUtil.getURL_ZBLst(mEnumType), new IListener() {
@Override
public void onCall(String t) {
if (t == null) {
Toast.makeText(MaterialGridWithTypeActivity.this, "没有符合条件的物品",
Toast.LENGTH_SHORT).show();
return;
}
// 获得物品列表Json后,转换为所需要的对象列表
AppContext.getApp().getJsonManager().parseList(t, MaterialSimple.class,
new IListener>() {
@Override
public void onCall(List lstMs) {
if(lstMs == null || lstMs.size() == 0){
Toast.makeText(MaterialGridWithTypeActivity.this, "没有符合条件的物品",
Toast.LENGTH_SHORT).show();
return;
}
mLstMs = lstMs;
// 依据物品id,构造物品的图片地址,在Adapter中将根据该地址获取对应的图片
mLstSnt = new ArrayList();
for (MaterialSimple ms : lstMs) {
SimpleNetTool snt = new SimpleNetTool(URLUtil
.getURL_ZBImg(ms.getId(),
EnumDPI.DPI64x64), ms
.getText());
mLstSnt.add(snt);
}
mAdapter.setLstNetTools(mLstSnt, AppContext
.getApp().getImgLoader(), mDisPlayOption);
mAdapter.notifyDataSetChanged();
}
});
}
});
mGv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
openMaterialDetail("" + mLstMs.get(position).getId());
}
});
}
/**
* 打开物品详情界面
* @param materialId
*/
private void openMaterialDetail(String materialId) {
Intent it = new Intent(this, MaterialDetailActivity.class);
it.putExtra(MaterialDetailActivity.EXTRA_MATERIALID, materialId);
startActivity(it);
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
}
}
物品详情界面
/**
* 物品详情
* @author warren
* @date 2014年12月31日
*/
public class MaterialDetailActivity extends Activity {
public static final String EXTRA_MATERIALID = "EXTRA_MATERIALID";
private ImageView mImgLeft;
private ImageView mImgRight;
private TextView mTvTitle;
private LinearLayout mLlRoot;
private ImageView mImgMaterial;
private TextView mTvMaterialName;
private TextView mTvMaterialPrice;
private TextView mTvDescription;
private LinearLayout mLlNeed;
private LinearLayout mLlCompose;
private ImageLoader mImgLoader;
private String mStrMaterialId;
private Material mMaterial;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_materialdetail);
mImgLoader = AppContext.getApp().getImgLoader();
mStrMaterialId = getIntent().getStringExtra(EXTRA_MATERIALID);
initCtrl();
}
private void initCtrl() {
mImgLeft = (ImageView) findViewById(R.id.img_title_left);
mImgRight = (ImageView) findViewById(R.id.img_title_right);
mTvTitle = (TextView) findViewById(R.id.tv_title);
mImgLeft.setImageResource(R.drawable.lolbox_titleview_return_default);
mImgRight.setVisibility(View.GONE);
mTvTitle.setText("物品详情");
mImgLeft.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
mLlRoot = (LinearLayout) findViewById(R.id.ll_root);
mLlNeed = (LinearLayout) findViewById(R.id.ll_need);
mLlCompose = (LinearLayout) findViewById(R.id.ll_compose);
mImgMaterial = (ImageView) findViewById(R.id.img_material);
mTvMaterialName = (TextView) findViewById(R.id.tv_materialname);
mTvMaterialPrice = (TextView) findViewById(R.id.tv_materialmoney);
mTvDescription = (TextView) findViewById(R.id.tv_materialdescription);
if (mStrMaterialId == null) {
setNullHint();
return;
}
// 请求服务器获取物品详情Json
AppContext.getApp()
.getNetManager()
.get(URLUtil.getURL_ZBDetail(Integer.parseInt(mStrMaterialId)),
new IListener() {
@Override
public void onCall(String strJson) {
strJson = checkMaterialJson(strJson);
// 获取到Json后解析成 Material实体
AppContext.getApp()
.getJsonManager()
.parse(strJson, Material.class,
new IListener() {
@Override
public void onCall(
Material material) {
if (material == null) {
setNullHint();
return;
}
mMaterial = material;
setView();
}
});
}
});
}
/**
* 纠正服务器传回的Json。
* @description
* 请求生命药水、法力药水等“没有需求物品也没有合成物品”的工具类物品的物品详情时,服务器返回的Json中,
* extAtts的值是 "extAttrs":[] 格式,这与Material
* 类的extAttrs所需求的Map格式不符,需矫正,否则会解析失败。
* @param strJson
* @return
*/
private String checkMaterialJson(String strJson) {
if (strJson.contains("\"extAttrs\":[]")) {
strJson = strJson.replace("\"extAttrs\":[]", "\"extAttrs\":{}");
}
return strJson;
}
/**
* 依据物品详情设置界面
*/
private void setView() {
mTvDescription.setText(mMaterial.getDescription());
mTvMaterialName.setText(mMaterial.getName());
mTvMaterialPrice.setText("价格:" + mMaterial.getPrice() + " 总价:" + mMaterial.getAllPrice()
+ " 售价:" + mMaterial.getSellPrice());
mImgLoader.displayImage(
URLUtil.getURL_ZBImg(Integer.parseInt(mMaterial.getId()), EnumDPI.DPI64x64),
mImgMaterial);
String[] arrNeedId = mMaterial.getNeed() == null ? null : mMaterial.getNeed().split(",");
String[] arrComposeId = mMaterial.getCompose() == null ? null : mMaterial.getCompose()
.split(",");
if (arrNeedId != null) {
for (String strNeedId : arrNeedId) {
if (StringUtils.isNullOrZero(strNeedId)) {
continue;
}
mLlNeed.addView(createMaterialImg(strNeedId));
}
}
if (arrComposeId != null) {
for (String strComposeId : arrComposeId) {
if (StringUtils.isNullOrZero(strComposeId)) {
continue;
}
mLlCompose.addView(createMaterialImg(strComposeId));
}
}
}
/**
* 设置查找物品详情失败的提示
*/
private void setNullHint() {
mLlRoot.removeAllViews();
TextView tvHint = new TextView(this);
tvHint.setText("查找物品详情失败");
mLlRoot.addView(tvHint);
}
/**
* 根据物品ID构建对应的ImageView,所需图片从服务器请求,点击事件也已在这里设置。
* @param materialId
* @return
*/
private ImageView createMaterialImg(final String materialId) {
ImageView img = new ImageView(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
DeviceUtil.dp2Px(this, 40), DeviceUtil.dp2Px(this, 40));
params.leftMargin = DeviceUtil.dp2Px(this, 2);
params.rightMargin = DeviceUtil.dp2Px(this, 2);
img.setLayoutParams(params);
mImgLoader.displayImage(
URLUtil.getURL_ZBImg(Integer.parseInt(materialId), EnumDPI.DPI64x64), img);
img.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
openMaterialDetail(materialId);
}
});
return img;
}
/**
* 打开物品详情界面
* @param materialId
*/
private void openMaterialDetail(String materialId) {
Intent it = new Intent(this, MaterialDetailActivity.class);
it.putExtra(MaterialDetailActivity.EXTRA_MATERIALID, materialId);
startActivity(it);
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
}
}
/**
* 物品bean
* @author warren
* @date 2014年12月30日
*/
public class Material {
private String id;
private String name;
private String description;
private Map extAttrs;
private String need;
private String compose;
private String extDesc;
private int price;
private int allPrice;
private int sellPrice;
private String tags;
public Material() {
super();
}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
/**
* @return the extAttrs
*/
public Map getExtAttrs() {
return extAttrs;
}
/**
* @param extAttrs the extAttrs to set
*/
public void setExtAttrs(Map extAttrs) {
this.extAttrs = extAttrs;
}
/**
* @return the need
*/
public String getNeed() {
return need;
}
/**
* @param need the need to set
*/
public void setNeed(String need) {
this.need = need;
}
/**
* @return the compose
*/
public String getCompose() {
return compose;
}
/**
* @param compose the compose to set
*/
public void setCompose(String compose) {
this.compose = compose;
}
/**
* @return the extDesc
*/
public String getExtDesc() {
return extDesc;
}
/**
* @param exDesc the exDesc to set
*/
public void setExtDesc(String extDesc) {
this.extDesc = extDesc;
}
/**
* @return the price
*/
public int getPrice() {
return price;
}
/**
* @param price the price to set
*/
public void setPrice(int price) {
this.price = price;
}
/**
* @return the allPrice
*/
public int getAllPrice() {
return allPrice;
}
/**
* @param allPrice the allPrice to set
*/
public void setAllPrice(int allPrice) {
this.allPrice = allPrice;
}
/**
* @return the sellPrice
*/
public int getSellPrice() {
return sellPrice;
}
/**
* @param sellPrice the sellPrice to set
*/
public void setSellPrice(int sellPrice) {
this.sellPrice = sellPrice;
}
/**
* @return the tags
*/
public String getTags() {
return tags;
}
/**
* @param tags the tags to set
*/
public void setTags(String tags) {
this.tags = tags;
}
}
/**
* 简化版的物品bean
* @author warren
* @date 2014年12月31日
*/
public class MaterialSimple {
private int id;
private String text;
public MaterialSimple(){
}
public MaterialSimple(int id, String text) {
super();
this.id = id;
this.text = text;
}
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the text
*/
public String getText() {
return text;
}
/**
* @param text the text to set
*/
public void setText(String text) {
this.text = text;
}
}
四、实现效果
五、说明
1,这些代码中使用到的 jar 包有 universal-image-loader, android-async-http, jacksonjson.
2,图片的请求使用 universal-image-loader来做缓存就已足够,其他网络访问的请求 暂时只做了内存缓存,没有存放在本地;官方应用的很多数据都是存放在了本地的,本地数据过期时会提醒下载最新的数据包;本地缓存的功能留待以后做。
3,由于官方应用的很多数据做了本地缓存,所以在操作功能时经常会不用 请求服务器,为了方便分析,可以把本地缓存清掉。缓存路径为 /sdcard/lolboxcache/ 。