前言

最近在学jQuery,今天来讲讲如何在web上利用jQuery动态生成列表,并对其每一个item做监听。


获取列表并对其进行遍历

一般的业务逻辑都是通过网络请求从后台中获取一个列表,在java中一般使用list存储。在js中就是一个数组了。

$.ajax({
        type:"POST",
        data:{userId:userId},
        url:server+"/order/getOrderByUserId",
        success:function (result) {
            if(result.code==200){
                createOrders(result.resultMap.list);
            }else{
                console.log(result);
                // showCommonModal(result.message);
            }
        },
        error:function (e) {
            alert("服务器异常,请稍后重试...");
        }
    });

这里我使用的是Ajax请求,result.resultMap.list就是我们所需要的列表集合了。

$.each(list,function (index,value) {
  ...
});

通过jQuery的$.each()就可以实现集合的遍历效果了,第一个参数list就是我们刚刚提到的列表集合,第二个参数传入一个函数,index是这个集合的下标(即0、1、2、3...),value是index对应的对象值。


通过集合遍历动态生成html

有了上述的遍历基础就可以正式通过遍历动态生成列表了。

  • 首先我们需要在html中编写一个div作为整个个动态生成列表的容器:

    <div class="content"></div>

  • 然后我们需要在遍历前创建一个变量:

    var item="";

  • 遍历的时候通过往该变量添加html:

     items+='<div class="container-fluid bg-white mt-2 item" id='+value.id+'>'+
                '<div class="row pt-2">'+
                    '<div class="col-8">' +
                        '<i class="fa fa-calendar mx-2" aria-hidden="true"></i><p class="d-inline-block date">'+value.createTime+'</p>'+
                    '</div>' +
                    '<div class="col-4"><p class="text-warning text-right align-items-center state">'+stateTxt+'</p></div>'+
                    '</div>' +
            '<div class="border-bottom"></div>' +
            '<p class="text-dark mt-2 books">'+value.bookName+'</p>'+
            '<div class="border-bottom"></div>' +
                '<div class="row mt-2">' +
                    '<div class="col-4 offset-8 text-right">合计:<i class="fa fa-jpy" aria-hidden="true"></i><p class="d-inline-block price">'+value.totalPrice+'</p></div>'+
                '</div>' +
            '</div>';
    
  • 最后通过append添加到之前定义的容器div中:

    $(".content").append(items);
    注:我们可以通过在div中添加自定义属性来存放我们在item监听中可能用到的数据:

items+='<div class="container-fluid bg-white mt-2 item" id='+value.id+'>'+

上述的id='+value.id+'就是一个自定义属性,当我们需要取出使用时可以通过以下写法来获取刚刚存进去的值:

var id=$(this).attr("id");

这样就完成了整个列表的动态生成了,这里我做的是一个订单列表,整个函数方法如下:

function createOrders(orders) {
var items="";
$.each(orders,function (index,value) {
    var stateTxt;
    if(value.state == "1"){
        stateTxt="待付款"
    }else if(value.state == "2"){
        stateTxt="待收货"
    }else if(value.state == "3"){
        stateTxt="已收货"
    }
    items+='<div class="container-fluid bg-white mt-2 item" id='+value.id+'>'+
                '<div class="row pt-2">'+
                    '<div class="col-8">' +
                        '<i class="fa fa-calendar mx-2" aria-hidden="true"></i><p class="d-inline-block date">'+value.createTime+'</p>'+
                    '</div>' +
                    '<div class="col-4"><p class="text-warning text-right align-items-center state">'+stateTxt+'</p></div>'+
                    '</div>' +
            '<div class="border-bottom"></div>' +
            '<p class="text-dark mt-2 books">'+value.bookName+'</p>'+
            '<div class="border-bottom"></div>' +
                '<div class="row mt-2">' +
                    '<div class="col-4 offset-8 text-right">合计:<i class="fa fa-jpy" aria-hidden="true"></i><p class="d-inline-block price">'+value.totalPrice+'</p></div>'+
                '</div>' +
            '</div>';
});
$(".content").append(items);
}

如何监听每个item的事件

$(".content").on('click','.item',function () {
   ...
})

我们需要通过注册上述那个列表容器的div也就是这里的.content的on事件来实现item事件的监听。on函数里面第一个参数是需要监听的事件,比如click点击事件;第二个参数是需要监听的位置,比如整个item(这里定义了每个item的div为.item),第三个参数就是监听是的函数回调了。


最后

最后看看效果图

前言

这篇文章总结一下一些代码优化的问题,本文出自代码优化


String字符串优化

最常见的例子就是当你要频繁操作一个字符串时,使用StringBuffer代替String。
还比如:使用int数组而不是Integer数组。
避免创建短命的临时对象,减少对象的创建就能减少垃圾收集,进而减少对用户体验的影响。


ListView优化

  • Item布局,层级越少越好,使用hierarchyview工具查看优化。
  • 复用convertView
  • 使用ViewHolder
  • item中有图片时,异步加载
  • 快速滑动时,不加载图片
  • item中有图片时,应对图片进行适当压缩
  • 实现数据的分页加载

减少不必要的全局变量

尽量避免static成员变量引用资源耗费过多的实例,比如Context。
因为Context的引用超过它本身的生命周期,会导致Context泄漏。所以尽量使用Application这种Context类型。
你可以通过调用Context.getApplicationContext()或 Activity.getApplication()轻松得到Application对象。


Cursor(游标)回收

Cursor是Android查询数据后得到的一个管理数据集合的类,在使用结束以后。应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android明显是倾向于编程者手动的将Cursor close掉,因为在源代码中我们发现,如果等到垃圾回收器来回收时,会给用户以错误提示。


Receiver(接收器)回收

调用registerReceiver()后未调用unregisterReceiver().
当我们Activity中使用了registerReceiver()方法注册了BroadcastReceiver,一定要在Activity的生命周期内调用unregisterReceiver()方法取消注册
也就是说registerReceiver()和unregisterReceiver()方法一定要成对出现,通常我们可以重写Activity的onDestory()方法,在onDestory里进行unregisterReceiver操作


Stream/File(流/文件)回收

主要针对各种流,文件资源等等如:
InputStream/OutputStream,SQLiteOpenHelper,SQLiteDatabase,Cursor,文件,I/O,Bitmap图片等操作等都应该记得显示关闭。


避免内部Getters/Setters

在Android中,虚方法调用的代价比直接字段访问高昂许多。通常根据面向对象语言的实践,在公共接口中使用Getters和Setters是有道理的,但在一个字段经常被访问的类中宜采用直接访问。
for循环
访问成员变量比访问本地变量慢得多,如下面一段代码:

for(int i =0; i < this.mCount; i++)  {}  

永远不要在for的第二个条件中调用任何方法,如下面一段代码:

for(int i =0; i < this.getCount(); i++) {}  

对上面两个例子最好改为:

int count = this.mCount; / int count = this.getCount();  
for(int i =0; i < count; i++)  {}

前言

这篇文章主要对优化ListView作简单的笔记,本文主要参考ListView的优化


ListView的RecycleBin机制

ListView被多次调用的方法就是适配器Adapter中的getView方法。getView方法需要返回一个View对象作为每个item的视图。简单来说,item的有多少个就会调用多少次getView方法。但并不是有多少个item就会创建多少个View,这样对于内存优化来说是很不友好的,如果View里面包含很多图片或者控件的话,估计手机都会卡死了。所以ListView里有一个RecycleBin机制,它会自动回收视图已经不可见的View对象,然后在滚动条向下滑动的时候将回收的View对象作为底部新出现的item来使用。所以getView方法的参数中有一个View convertView。具体可参考上述的链接,里面有详细的图片说明。


引入ViewHolder

  • 对布局的优化

按照上述的机制我们可以对convertView作一层判断,因为列表中item的布局一般都是使用同一个布局(当然也会出现多布局的情况,但是使用ListView不是特别方便)。根据上述的方案,在getView中就会有如下的写法:

if(convertView==null){  
  convertView=LayoutInflater.from(mContext).inflate(R.layout.activity_main,null);
}else{

}

首先判断convertView是否为null,如果是则将布局xml与其绑定。这里就遵循一个原则:item的布局是不变的,变的只是布局里面的内容。

  • 对控件的优化
    上述的方法只是对convertView这一布局做了优化而已,由于getView方法频繁被调用,这就意味着如果按照上述的写法,布局中的控件就会被频繁的创建,如:
TextView textView=convertView.findViewById(R.id.text);

这样也会增加内存的压力。所以我们可以引入一个ViewHolder的概念,这个其实在RecyclerView中已经是常规性操作了。

class ViewHolder{
    TextView textView;

    public ViewHolder(View itemView) {
        textView=itemView.findViewById(R.id.text);
    }
}

在Adapter中编写一个ViewHolder的内部类,我们可以将上述的TextView写成这个类的成员变量,然后在其构造方法中利用convertView来初始化TextView,然后将这个ViewHolder对象用convertView.setTag方法保存起来。

ViewHolder holder;
if(convertView==null){
   convertView=LayoutInflater.from(mContext).inflate(R.layout.activity_main,null);
   holder=new ViewHolder(convertView);
   convertView.setTag(holder);
}else{
   holder= (ViewHolder) convertView.getTag();
}

当convertView不是null的时候我们就可以从中取出这个ViewHolder,这样就避免了控件重复创建的问题了。


其它

关于ListView的优化其实还有很多,譬如如果item中包含图片的话还需注意资源回收的问题。还有就是static关键字的问题,譬如将Context对象定义成static的话就很容易造成内存泄漏。


总结

以下是对ListView的优化作一次总结:

  • Item布局,层级越少越好,使用hierarchyview工具查看优化。
  • 复用convertView
  • 使用ViewHolder
  • item中有图片时,异步加载
  • 快速滑动时,不加载图片
  • item中有图片时,应对图片进行适当压缩
  • 实现数据的分页加载