一步步实现 仿制Android LOL多玩盒子(二) 物品装备相关
2014-12-31 16:26
357 查看
一、原应用相关模块简介
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<String, String> cache = new LruCache<String, String>(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<String> 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比较大时,解析操作是比较耗时的,这里把解析操作封装为异步解析,同步回调。
/** * 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 <T> void parse(final String strJson, final Class<T> cls, final IListener<T> listener) { new AsyncTaskParser<T>(listener, cls).execute(strJson); } /** * 异步解析列表Json,同步回调。解析成功则回调方法中的参数是解析结果,否则是 null。 * @param strJson * @param cls * @param listener */ public <T> void parseList(final String strJson, final Class<T> cls, final IListener<List<T>> listener) { new AsyncTaskParserList<T>(cls, listener).execute(strJson); } /** * 异步解析列表Json,同步回调 * @author warren * @date 2014年12月31日 * @param <T> */ class AsyncTaskParserList<T> extends AsyncTask<String, Integer, List<T>> { private Class<T> cls; private IListener<List<T>> listener; public AsyncTaskParserList(Class<T> cls, IListener<List<T>> listener) { this.listener = listener; this.cls = cls; } @Override protected List<T> doInBackground(String... params) { StringReader sr = new StringReader(params[0]); List<T> lst = new ArrayList<T>(); try { sr.reset(); // 解析成List时,无法直接解析成指定类型的列表,所以需要把解析得到的List<HashMap<String, // Object>>每一项单独再转成指定类型的对象。 JsonFactory factory = new ObjectMapper().getJsonFactory(); JsonParser jpar = factory.createJsonParser(sr); List<HashMap<String, Object>> mapLst = jpar.readValueAs(List.class); for (HashMap<String, Object> 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<T> result) { super.onPostExecute(result); listener.onCall(result); } } /** * 异步解析Json,同步回调 * @author warren * @date 2014年12月31日 * @param <T> */ class AsyncTaskParser<T> extends AsyncTask<String, Integer, T> { private IListener<T> listener;; private Class<T> cls; public AsyncTaskParser(IListener<T> listener, Class<T> 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的通用适配器
/** * 通用的GridView的Adapter,支持 {@link SimpleTool} 和 {@link SimpleNetTool}列表的显示 * @author yangsheng * @date 2014年12月31日 */ public class BaseGridAdapter extends BaseAdapter { private LayoutInflater inflater; private List<SimpleTool> lstTools; private List<SimpleNetTool> lstNetTools; private ImageLoader imgLoader; private DisplayImageOptions options; private int numColumn = 3; public BaseGridAdapter(LayoutInflater inflater) { this.inflater = inflater; } public void setLstTools(List<SimpleTool> lstTools) { this.lstTools = lstTools; } public void setLstNetTools(List<SimpleNetTool> 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<MaterialSimple> mLstMs; private List<SimpleNetTool> 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<String>() { @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<List<MaterialSimple>>() { @Override public void onCall(List<MaterialSimple> lstMs) { if(lstMs == null || lstMs.size() == 0){ Toast.makeText(MaterialGridWithTypeActivity.this, "没有符合条件的物品", Toast.LENGTH_SHORT).show(); return; } mLstMs = lstMs; // 依据物品id,构造物品的图片地址,在Adapter中将根据该地址获取对应的图片 mLstSnt = new ArrayList<SimpleNetTool>(); 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<String>() { @Override public void onCall(String strJson) { strJson = checkMaterialJson(strJson); // 获取到Json后解析成 Material实体 AppContext.getApp() .getJsonManager() .parse(strJson, Material.class, new IListener<Material>() { @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<String, String> 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<String, String> getExtAttrs() { return extAttrs; } /** * @param extAttrs the extAttrs to set */ public void setExtAttrs(Map<String, String> 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/ 。
相关文章推荐
- 一步步实现 仿制Android LOL多玩盒子(三) 英雄基础
- 一步步实现 仿制Android LOL多玩盒子(一) 概览
- 一步步实现 仿制Android LOL多玩盒子(四) 自定义AlertDialog实现
- Android自定义View的实现方法,带你一步步深入了解View(四)
- 全屏实现-去除android盒子底部的虚拟导航按键
- android定时服务实现的相关开源包
- Android显示网络图片相关实现方法浅谈
- 基于avd7181c解决视频输入效果差的问题<四>---android显示相关实现调试手记
- Android自定义View的实现方法,带你一步步深入了解View(四)
- Android 进阶学习:Android自定义View的实现方法,带你一步步深入了解View(四)
- Android自定义View的实现方法,带你一步步深入了解View(四)
- Android实现获取应用程序相关信息列表的方法
- Android使用MediaRecorder实现录音功能相关知识
- Android自定义View的实现方法,带你一步步深入了解View(四)
- Android自定义View的实现方法,带你一步步深入了解View(四)
- Android编程实现连接Wifi(运用Wifi 相关 API)
- android轻松实现背景的相关设置
- Android自定义View的实现方法,带你一步步深入了解View(四)
- Android自定义View的实现方法,带你一步步深入了解View(四)