[lottery] 02_购彩大厅(二)—ListView优化

Android 4.0

购彩大厅(二)
ListView优化一:
①convertView的复用,防止多次创建新的View耗费资源
②使用ViewHolder保存findViewById()找到的组件,防止多次查找id
③对于ListView中局部数据的变化,不必要全部更新ListView的每一个item,只要更新部分,
通过viewHolder.tv.setTag(position)来保存要更新数据组件的引用,position必须是唯一的标识
通过ListView.findViewWithTag(position)来查找View对象
④ListView懒加载,滚动时不加载数据,停止下来的时候加载数据

技术点:1、ListView的配置信息:
①android:divider = "@null" 默认的分割线去掉
②android:listSelector = "@android/color/white" 默认点击的时候的效果
2、ListView的Tag使用
①保存数据
convertView.setTag(viewHolder);
②唯一的标识一个组件(ListView的每一个位置的id都相同,所以用当前位置来标识)
viewHolder.tv.setTag(position) //一般用当前位置position来唯一的标识当前组件
3、ListView中,对于要更新数据,使用adapter.notifyDataSetChanged()来更新数据时,
会将每一个ListView中的item给刷新,如果要更新的ListView中每一个条目的图片基本不变化,且图片很多,那么界面将会很卡顿,所以只对需要更新的部位进行更新
①用一个List<TextView> tv按位置记录下要改变数据的组件的引用,然后在数据更新时直接从集合中将需要改变数据的tv引用取出来更新数据
②但①中有一个问题:需要手动的在ListView中维护一个ListView,所以用viewHolder.tv.setTag(position)
position为当前位置(唯一的),来唯一的标识当前tv,然后在取出来的时候通过:
ListView.findViewWithTag(position);来取出对应position的组件,然后进行更新数据,这个就不需要手动的维护一个ListView了。
4、什么时候用notifyDataSetChanged(),什么时候用findViewWithTag()?
①当ListView中需要进行增删item时候notifyDataSetChanged();
②当需要更新Item中信息时候,一般使用优化的方式完成,
5、ListView懒加载
ListView滚动的时候不加载数据(不往item添加数据),在停下来的时候加载数据
步骤:
lListView形式展示多彩种入口
    1、快速完成Adapter工作
    2、更新当前销售期信息
方案一:将获取到服务器信息设置到Map中,以positionkey(临时方案),后执行adapternotifay进行数据更新
方案二:在adaptergetView初始化时将TextView的引用设置到List中,当获取到服务器数据后更新相应的TextView
方案三:利用ViewfindViewWithTag方法进行更新处理
l    3、扩展使用
① 时间更新
② 图片加载
l
核心代码:
package cn.zengfansheng.lottery.view;
import org.apache.commons.lang3.StringUtils;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import cn.zengfansheng.lottery.ConstantValue;
import cn.zengfansheng.lottery.R;
import cn.zengfansheng.lottery.engine.CommonInfoEngine;
import cn.zengfansheng.lottery.factory.EngineFactory;
import cn.zengfansheng.lottery.net.protocol.Message;
import cn.zengfansheng.lottery.net.protocol.Olement;
import cn.zengfansheng.lottery.net.protocol.element.CurrentIssueElement;
import cn.zengfansheng.lottery.util.LogUtil;
import cn.zengfansheng.lottery.util.PromptManager;
public class HallView extends BaseView {

    // *****************属性声明*******************//
    private static final String TAG = "HallView";
    // 资源信息
    private static final int[] LOGORESIDS =  { R.drawable.id_ssq, R.drawable.id_3d, R.drawable.id_qlc };
    
    private static final int[] TITLERESIDS =   { R.string.is_hall_ssq_title, R.string.is_hall_3d_title, R.string.is_hall_qlc_title };
    
    //listview
    private ListView categoryList;
    //adapter
    private LotteryAdapter adapter;
    
    // 方案一: 保存当前销售期信息
    // private Map<Integer, String> data;

    // 方案二:
    // private List<TextView> tvLotterySummary;
    // *****************构造方法*******************//
    public HallView(Context context) {
        super(context);
    }
    // ********************ListView和ViewHolder****************//
    private static class ViewHolder {
        private ImageView ivHallLotteryLogo;// 彩种Logo
        private TextView tvHallLotteryTitle;// 彩种Title
        private TextView tvHallLotterySummary;// 概要信息
        private ImageView ivHallLotteryBet;// 投注
    }
    private class LotteryAdapter extends BaseAdapter{
//        private  int[] LOGORESIDS =  { R.drawable.id_ssq, R.drawable.id_3d, R.drawable.id_qlc };
//        private  int[] TITLERESIDS =   { R.string.is_hall_ssq_title, R.string.is_hall_3d_title, R.string.is_hall_qlc_title };
        
        @Override
        public int getCount() {
            return LOGORESIDS.length;// FIXME:这里logoResIds如果不做成静态的或者不放在LotteryAdapter中,那么将获取不到这个数组的长度。
        }
        @Override
        public Object getItem(int position) {
            return null;
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            
            LogUtil.i(TAG"getView");
            View view = null;
            ViewHolder viewHolder = null;
            if (convertView != null && convertView instanceof LinearLayout) {
                view = convertView;
                viewHolder = (ViewHolder) view.getTag();
            } else {
                view = View.inflate(context, R.layout.zl_hall_lottery_itemnull);
                
                viewHolder = new ViewHolder();
                viewHolder.ivHallLotteryLogo = (ImageView) view.findViewById(R.id.iv_hall_lottery_logo_zl);
                viewHolder.tvHallLotteryTitle = (TextView) view.findViewById(R.id.tv_hall_lottery_title_zl);
                viewHolder.tvHallLotterySummary = (TextView) view.findViewById(R.id.tv_hall_lottery_summary_zl);
                viewHolder.ivHallLotteryBet = (ImageView) view.findViewById(R.id.iv_hall_lottery_bet_zl);
                
                // 方案二:保存每一个需要变动的内容:tvHallLotterySummary
                // tvLotterySummary.add(viewHolder.tvHallLotterySummary);

                // 方案三:
                viewHolder.tvHallLotterySummary.setTag(position);// tag的用法二:唯一的标示一个控件

                view.setTag(viewHolder);// tag的用法一:存储数据
            }
            // logo
            viewHolder.ivHallLotteryLogo.setImageResource(LOGORESIDS[position]);
            // title
            viewHolder.tvHallLotteryTitle.setText(TITLERESIDS[position]);

            // 方案一:保存当前销售期信息到map
            //String info = data.get(position);
            //if (StringUtils.isNotBlank(info)) {
            //    viewHolder.tvHallLotterySummary.setText(info);
            //}

            viewHolder.ivHallLotteryBet.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    switch (position) {
                            case 0:// 双色球
                                    // TODO: 双色球投注bet
                        
                        break;
                        }
                    }
            });
            return view;
        }
    } 
    
    // ********************初始化购物大厅组件****************//
    /**
     * 1、初始化购物大厅组件
     */
    public void init() {
        // 1、showView
        showView = (ViewGroup) View.inflate(context, R.layout.zl_hallnull);
        
        // 2、listview初始化
        categoryList = (ListView) showView.findViewById(R.id.lv_category_selector);

        // 方案一:存储当前销售期信息(不变的内容也刷新,耗费资源,卡顿)
        // data = new HashMap<Integer, String>();

        // 方案二:保存要改变的TextView的引用(需要手动在ListView集合中维护一个List集合)
        // tvLotterySummary = new ArrayList<TextView>();

        // 3、adapter初始化
        adapter = new LotteryAdapter();
        
        // 4、设置adapter
        categoryList.setAdapter(adapter);
    }
    
    @Override
    public void setListener() {
    }
    @Override
    public void onResume() {
        getCurrentIssueInfo();
    }
    @Override
    public int getViewId() {
        return ConstantValue.VIEW_HALL;
    }
    // **************************修改界面的提示信息****************************//
    /**
     * 修改界面的提示信息
     * 
     * @param element
     */
    private void changeNotice(CurrentIssueElement element) {
        String info = context.getResources().getString(
                R.string.is_hall_common_summary);
        // 当前期次
        String issue = element.getIssue();
        // 剩余投注时间
        String lasttime = element.getLasttime();
        info = StringUtils.replaceEach(info, new String[] { "ISSUE""TIME" },
                new String[] { issue, getLasttime(lasttime) });

        // 方案一:将从服务器获取到的数据存储到Map<Integer,String>
        // data中(存储当前销售期信息(不变的内容也刷新,耗费资源,卡顿))
        // 方案一问题:每次获取数据都会刷新一下listview的item,但有的东西不需要变化
        // data.put(0, info);
        // adapter.notifyDataSetChanged();// 让每一个listview的item刷新一下

        // 方案二:现在listview中需要改变的只有textview中的内容,阶段只需要更新TextView的显示内容,与item其他空间没有关系
        // 解决:创建一个集合在getView向集合添加TextView的引用
        // 方案二问题:ListView需要维护一个List集合
        // TextView tvSummery = tvLotterySummary.get(0);
        // tvSummery.setText(info);

        // 方案三:tag
        TextView tvSummery = (TextView) categoryList.findViewWithTag(0);// 将对应位置的组件取出来
        tvSummery.setText(info);

            // note:什么时候用notifyDataSetChanged(),什么时候用findViewWithTag()?
        // 当ListView中需要进行增删item时候notifyDataSetChanged();
        // 当需要更新Item中信息时候,一般使用优化的方式完成,
        // ③扩展:ListView懒加载,ListView滚动的时候不加载数据(不往item添加数据),在停下来的时候加载数据
    }
    
    // ********************************异步的从服务器上获取数据************************************//
    /**
     * 获取当前销售期信息(从服务器上获取最新数据)
     */
    public void getCurrentIssueInfo(){
        // 优化3:使用已有AsyncTask类进行数据的获取,将其丢到BaseView中
        new MyHttpAsyncTask<Integer>() {
            @Override
            protected Message doInBackground(Integer... params) {
                // 1、获取业务的对象(用工厂类来获取)
                CommonInfoEngine infoEngine = EngineFactory.getEngineImplInstance(CommonInfoEngine.class);
                // 2、执行相应的方法
                Message message = infoEngine.getCurrentIssueInfo(params[0]);
                return message;
            }
            @Override
            protected void onPostExecute(Message result) {
                super.onPostExecute(result);
                // 界面的展示
                if (result != null) {// 从服务器上获取的message不为null
                    Olement olement = result.getBody().getOlement();
                    if (0 == (olement.getErrorcode())) {// 服务器返回正确,为0
                        CurrentIssueElement element = (CurrentIssueElement) result.getBody().getElements().get(0);
                        changeNotice(element);
                    } else {// 服务器返回不正确
                        PromptManager.showToast(context, olement.getErrormsg());
                    }
                } else {// 没有拿到数据
                    PromptManager.showToast(context"您好,服务器繁忙,请稍后再试!");
                }
            }
        }.executeProxy(ConstantValue.SSQ);
    }
    /**
     * 将秒时间转换成日时分格式
     * 
     * @param lasttime
     * @return
     */
    public String getLasttime(String lasttime) {
        StringBuffer result = new StringBuffer();
        if (StringUtils.isNumericSpace(lasttime)) {
            int time = Integer.parseInt(lasttime);
            int day = time / (24 * 60 * 60);
            result.append(day).append("天");
            if (day > 0) {
                time = time - day * 24 * 60 * 60;
            }
            int hour = time / 3600;
            result.append(hour).append("时");
            if (hour > 0) {
                time = time - hour * 60 * 60;
            }
            int minute = time / 60;
            result.append(minute).append("分");
        }
        return result.toString();
    }
 }