2017-10-19 16:05:25 wangzhongshun 阅读数 9711
  • Python入门视频教程

    购买课程后,请扫码进入学习群,获取唐宇迪老师答疑 Python入门基础教程:python教程旨在掌握python开发的入门基础用法与其核心操作,便于大家在短时间内可以使用python进行后续的工作与学习。课程内容包括Python环境搭建(Anaconda方式)、变量、List基础结构、List索引、循环结构、判断结构、字典结构、文件处理、函数基础等。

    18148 人正在学习 去看看 唐宇迪

Android中一般使用的数据结构有java中的基础数据结构List,Set,Map。还有一些Android中特有的几个,SparseArray(使用Map时Key是int类型的时候可以用这个代替)等。

继承关系:

Collection<–List<–ArrayList

Collection<–List<–Vector

Collection<–List<–LinkedList

Collection<–Set<–HashSet

Collection<–Set<–HashSet<–LinkedHashSet

Collection<–Set<–SortedSet<–TreeSet

Map<–HashMap (补充一个HashMap的子类LinkedHashMap:)

Map<–SortedMap<–TreeMap

注:这里的 Collection、List、Set和Map都是接口(Interface),其中Collection是所有集合类的接口,Set和List也都实现该接口。

下面分别来介绍List、Set、Map。

List

List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。 List比较常用的有ArrayList和LinkedList,还有一个比较类似的Vector。

1、ArrayList

基于数组(Array)的List,ArrayList其实是对数组的动态扩充,底层的数据结构使用的是数组结构(数组长度是可变的百分之五十延长)。

特点:

对于数据的随机get和set或是少量数据的插入或删除,效率会比较高。ArrayList是线程不安全的,在不考虑线程安全的情况下速度也比较快的。ArrayList插入数据可以重复,也是有序的,按照插入的顺序来排序。性能上要比Vector(是线程安全的)好一些。

Vector

基于数组(Array)的List,Vector其实是对数组的动态扩充,底层的数据结构使用的是数组结构(数组长度是可变的百分之百延长)。

特点:

Vector的使用方法和内部实现基本和ArrayList相同,只不过它在add(), remove(), get()等方法中都加了同步。所以Vector是线程同步(sychronized)的,线程安全的。但是使用效率上就不如ArrayList了。

LinkedList

LinkedList不同于前面两个,是基于链表实现的双向链表数据结构。
它每一个节点(Node)都包含三方面的内容:

1、节点本身的数据(data)

2、前一个节点的信息(previousNode)

3、下一个节点的信息(nextNode)

所以当对LinkedList做添加,删除动作的时候就不用像基于数组的ArrayList一样,必须进行大量的数据移动。
只要更改nextNode的相关信息就可以实现了,这是LinkedList的优势。

LinkedList根据序号获取数据,是根据二分法进行遍历,如果序号小于总长度的一半,就从链表头部开始往后遍历,直到找到对应的序号。如果序号大于总长度的一半,就从链表尾部往前进行遍历,直到找到对应的序号。拿到数据。

List总结

1、所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[ tom,1,c ]

2、所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ]

3、所有的List中可以有null元素,例如[ tom,null,1 ]

4、基于Array的List(Vector,ArrayList)适合查询,而LinkedList 适合添加,删除操作

Set

Set是一种不包含重复的元素的无序Collection。 一般使用的有HashSet和TreeSet。

虽然Set同List都实现了Collection接口,但是他们的实现方式却大不一样。List基本上都是以Array为基础。但是Set则是在 HashMap的基础上来实现的,这个就是Set和List的根本区别。

HashSet

HashSet是根据hashCode来决定存储位置的,是通过HashMap实现的,所以对象必须实现hashCode()方法,存储的数据无序不能重复,可以存储null,但是只能存一个。

看看 HashSet的add(Object obj)方法的实现就可以一目了然了。

public boolean add(Object obj) {   
   return map.put(obj, PRESENT) == null;   
}

这个也是为什么在Set中不能像在List中一样有重复的项的根本原因,因为HashMap的key是不能有重复的。

HashSet代码示例:

public class Main {

    public static void main(String[] args) throws IOException {
        hashSet();
    }

    public static void hashSet(){
        Set<String> set = new HashSet<String>();
        set.add("2");
        set.add("1");
        set.add(null);
        set.add("1");

        for(String s : set){
            System.out.println(s);
        }
    }
}

运行结果:

null
1
2

LinkedHashSet

HashSet的一个子类,一个链表。

它和HashSet的区别就在于LinkedHashSet的元素严格按照放入顺序排列。LinkedHashSet内部使用LinkedHashMap实现,所以它和HashSet的关系就相当于HashMap和LinkedHashMap的关系。如果你想让取出元素的顺序和插入元素的顺序完全相同,那么就使用LinkedHashSet代替HashSet。

LinkedHashSet也不是线程安全的。

TreeSet

SortedSet的子类,它不同于HashSet的根本就是TreeSet是有序的。它是通过SortedMap来实现的。TreeSet是根据二叉树实现的,也就是TreeMap,,放入数据不能重复且不能为null,可以重写comparator()方法来确定元素大小,从而进行升序排序。

代码示例:

public class Main {

    public static void main(String[] args) throws IOException {
        treeSet();
    }

    public static void treeSet(){
        //通过传入MyComparator对象自定义的排序方法,来实现从大到小的排序。
        Set<Integer> treeSet = new TreeSet<>(new MyComparator());
        treeSet.add(1);
        treeSet.add(3);
        treeSet.add(4);
        treeSet.add(2);

        for(Integer i : treeSet){
            System.out.println(i);
        }
    }

    static class MyComparator implements Comparator<Integer>{

        @Override
        public int compare(Integer o1, Integer o2) {
            if(o1 < o2 ){
                return -1;
            }
            if(o1 == o2 ){
                return 0;
            }
            if(o1 > o2 ){
                return 1;
            }
            return 0;
        }
    }
}

运行结果:

1
2
3
4

Set总结

1、Set实现的基础是Map(HashMap)

2、Set中的元素是不能重复的,如果使用add(Object obj)方法添加已经存在的对象,则会覆盖前面的对象

Map

Map 是一种把键对象和值对象进行关联的容器,而一个值对象又可以是一个Map,依次类推,这样就可形成一个多级映射。

对于键对象来说,像Set一样,一个 Map容器中的键对象不允许重复,这是为了保持查找结果的一致性;如果有两个键对象一样,那你想得到那个键对象所对应的值对象时就有问题了,可能你得到的并不是你想的那个值对象,结果会造成混乱,所以键的唯一性很重要,也是符合集合的性质的。

当然在使用过程中,某个键所对应的值对象可能会发生变化,这时会按照最后一次修改的值对象与键对应。对于值对象则没有唯一性的要求,你可以将任意多个键都映射到一个值对象上,这不会发生任何问题(不过对你的使用却可能会造成不便,你不知道你得到的到底是那一个键所对应的值对象)。

Map有两种比较常用的实现:HashMap和TreeMap。

HashMap

HashMap是基于散列链表来实现的,简单的来说,根据key算出一个hash值,确定一个存放index,但是hash值有可能会冲突重复,所以如果冲突的hash值就需要以链表的形式在同一个index存放了。详情请看HashMap原理和代码浅析这篇文章。

代码示例:

    Map<String, String> hashMap = new HashMap<>();
    //存储
    hashMap.put("1", "abc");
    hashMap.put("2", "bcd");

    //根据key来删除
    hashMap.remove("1");
    //根据key获取
    String value = hashMap.get("2");

    //map的遍历,有很多方法遍历,这里只列举一种。
    for(Map.Entry<String, String> entry : hashMap.entrySet()){
        //获取key
        entry.getKey();
        //获取value
        entry.getValue();
    }

LinkedHashMap

LinkedHashMap继承自HashMap,特点是内部存入数据是有顺序的,增加了记住元素插入或者访问顺序的功能,这个是通过内部一个双向的循环链表实现的。与 HashMap 一样,它可以为基本操作(add、contains 和 remove)提供稳定的性能,假定哈希函数将元素正确分布到桶中。由于增加了维护链接列表的开支,其性能很可能比 HashMap 稍逊一筹,不过这一点例外:LinkedHashMap 的 collection 视图迭代所需时间与映射的大小 成比例。HashMap 迭代时间很可能开支较大,因为它所需要的时间与其容量 成比例。

TreeMap

TreeMap的使用大致跟HashMap类似,但是内部实现是根据红黑树来实现的。红黑树是一种平衡有序的二叉树,TreeMap的插入删除查询都是依据红黑树的规则来进行的。可以参考 Java提高篇(二七)—–TreeMap

HashTable

HashMap和TreeMap都是线程不安全的,多线程操作的时候可能会造成数据错误。Hashtable是线程安全的。其他内部实现,与HashMap都是一样的。

常用类的比较

常用类

1.ArrayList:元素单个,效率高,多用于查询

2.Vector: 元素单个,线程安全,多用于查询

3.LinkedList:元素单个,多用于插入和删除

4.HashMap:元素成对,元素可为空

5.HashTable:元素成对,线程安全,元素不可为空

6.HashSet:元素单个,元素不可重复

Vector、ArrayList和LinkedList

大多数情况下,从性能上来说ArrayList最好

当集合内的元素需要频繁插入、删除时LinkedList会有比较好的表现

它们三个性能都比不上数组,另外Vector是线程同步的

能用数组的时候(元素类型固定,数组长度固定),请尽量使用数组来代替List

没有频繁的删除插入操作,又不用考虑多线程问题,优先选择ArrayList

在多线程条件下使用,可以考虑Vector

需要频繁地删除插入,LinkedList就有了用武之地

如果你什么都不知道,用ArrayList没错。

以上是java中的基础的数据结构,下面来看下android中特有的数据结构。

SparseArray

SparseArray类型

SparseLongArray

SparseIntArray

SparseBooleanArray

SparseArray

SparseArray特点

1、SparseArray是android提供的一个工具类,它可以用来替代hashmap进行对象的存储

2、SparseArray比HashMap更省内存,它对数据采取了矩阵压缩的方式来表示稀疏数组的数据,从而节约内存空间

3、SparseArray只能存储key为整型的数据

4、SparseArray在存储和读取数据时候,使用的是二分查找法,提高了查找的效率

5、SparseArray有自己的垃圾回收机制。(当数量不是很多的时候,这个不必关心。)

ArrayMap

官方对ArrayMap也有说明:它不是一个适应大数据的数据结构,相比传统的HashMap速度要慢,因为查找方法是二分法,并且当你删除或者添加数据时,会对空间重新调整,在使用大量数据时,效率并不明显,低于50%。

所以ArrayMap是牺牲了时间换区空间。在写手机app时,适时的使用ArrayMap,会给内存使用带来可观的提升。

HashMap和ArrayMap的区别

1、存储方式不同

2、添加数据时扩容时的处理不同

详情请参考Android内存优化:ArrayMap

2015-04-20 11:58:53 fancylovejava 阅读数 26175
  • Python入门视频教程

    购买课程后,请扫码进入学习群,获取唐宇迪老师答疑 Python入门基础教程:python教程旨在掌握python开发的入门基础用法与其核心操作,便于大家在短时间内可以使用python进行后续的工作与学习。课程内容包括Python环境搭建(Anaconda方式)、变量、List基础结构、List索引、循环结构、判断结构、字典结构、文件处理、函数基础等。

    18148 人正在学习 去看看 唐宇迪

####Android开发中高效的数据结构
android开发中,在java2ee或者android中常用的数据结构有Map,List,Set,但android作为移动平台,有些api(很多都是效率问题)显然不够理想,本着造更好轮子的精神,android团队编写了自己的api用来代替java api

1、SimpleArrayMap<K,V>与ArrayMap<K,V>

实质上ArrayMap继承自SimpleArrayMap,主要是为了实现像HashMap一样的api方法,让习惯使用HashMap的开发者感觉不到差异,本质上是SimpleArrayMap+Map的再封装。

一般来说使用这2个类主要来代替HashMap,因为他们比HashMap更加高效,对内存也进行了优化。

2、SparseArray<T>与SparseArrayCompat<T>和LongSparseArray<T>

这3个类中,前2个基本上是同一类,只不过第二个类有removeAt方法,第三个是Long类型的。

这3个类也是用来代替HashMap,只不过他们的键(key)的类型是整型Integer或者Long类型,在实际开发中,如月份缩写的映射,或者进行文件缓存映射,viewHolder都特别适用

3、AtomicFile

AtomicFile首先不是用来代替File的,而是作为File的辅助类从在, AtomicFile的作用是实现事务性原子操作,即文件读写必须完整,适合多线程中的文件读写操作。

用来实现多线程中的文件读写的安全操作

----
#####用SparseArray代替HashMap
SparseArray是android提供的一个工具类,它可以用来替代hashmap进行对象的存储,其内部实现了一个矩阵压缩算法,很适合存储稀疏矩阵的。

PS:support包中还提供了兼容的类SparseArrayCompat,基本和SparseArray是同一个类,只不过第二个类有removeAt方法

针对源码的详细分析:[http://stormzhang.com/android/2013/08/01/android-use-sparsearray-for-performance-optimization/](http://stormzhang.com/android/2013/08/01/android-use-sparsearray-for-performance-optimization/ "http://stormzhang.com/android/2013/08/01/android-use-sparsearray-for-performance-optimization/")

一、和Hashmap的对比

既然android推荐用这个东西,自然有用它的道理。其内部实现了压缩算法,可以进行矩阵压缩,大大减少了存储空间,节约内存。此外它的查找算法是二分法,提高了查找的效率。

替换原则:

1>

如果用到了: HashMap<Integer, E> hashMap = new HashMap<Integer, E>();

可以替换为:SparseArray<E> sparseArray = new SparseArray<E>();

2>

如果用到了:HashMap<Integer, Boolean> hashMap = new HashMap<Integer, Boolean>

可以替换为:SparseBooleanArray array = new SparseBooleanArray();

3>

如果用到了:HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>

可以替换为:SparseIntArray array = new SparseIntArray();

二、用法

既然是键值对那么就有增删改查,但要记得先初始化:


        Button btn = null; // 测试view,无意义
        Button btn02 = null; // 测试view,表示新增的对象
        final int KEY = 1;

        /*
         * SparseArray指的是稀疏数组(Sparse
         * array),所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用
         * 。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。
         */
        SparseArray<View> array = new SparseArray<View>();


 

2.1 增加数据


     /* 增加数据 */
        //public void put(int key, E value) {}
        array.put(KEY, btn);
        //public void append(int key, E value){}
        array.append(KEY, btn);


 

2.2 修改数据


      /* 修改数据 */
        //在put数据之前,会先查找要put的数据是否已经存在,如果存在就是修改,不存在就添加。
        //public void put(int key, E value)
        array.put(KEY, btn);
        //public void setValueAt(int index, E value)
        array.setValueAt(KEY, btn02);


 

2.3 查找数据


      /* 查找数据 */
        //public E get(int key)
        array.get(KEY);
        //public E get(int key, E valueIfKeyNotFound)
        //其中get(int key)也只是调用了 get(int key,E valueIfKeyNotFound),最后一个从传参的变量名就能看出,传入的是找不到的时候返回的值.get(int key)当找不到的时候,默认返回null。
        array.get(KEY, btn); // 如果这个key找不到value,那么就返回第二个参数。和default value一样


 

2.4 通过位置,查找键的值


      // 查看第几个位置的键:
        //public int keyAt(int index)
        array.keyAt(1); // 如果找不到就返回-1


 

2.5 通过位置,查找值


        // 查看第几个位置的值:
        //public E valueAt(int index)
        array.valueAt(1);
        // 查看值所在位置,没有的话返回-1:
        //public int indexOfValue(E value)
        array.indexOfValue(btn);



三、测试代码

    package com.kale.pictest;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    import android.util.SparseArray;
    import android.util.SparseBooleanArray;
    import android.view.View;
    import android.widget.Button;
    
    /**
     * @author:
     * @description  :
     * @web : http://stormzhang.com/android/2013/08/01/android-use-sparsearray-for-performance-optimization/
     * @date  :2015年1月19日
     */
    public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        Log.d("TAG", "Max memory is " + maxMemory + "KB");
        
        
        Button btn = null; // 测试view,无意义
        Button btn02 = null; // 测试view,表示新增的对象
        final int KEY = 1;

        /*
         * SparseArray指的是稀疏数组(Sparse
         * array),所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用
         * 。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。
         */
        SparseArray<View> array = new SparseArray<View>();
        
        /* 增加数据 */
        //public void put(int key, E value) {}
        array.put(KEY, btn);
        //public void append(int key, E value){}
        array.append(KEY, btn);
        
        /* 修改数据 */
        //在put数据之前,会先查找要put的数据是否已经存在,如果存在就是修改,不存在就添加。
        //public void put(int key, E value)
        array.put(KEY, btn);
        //public void setValueAt(int index, E value)
        array.setValueAt(KEY, btn02);
        
        /* 查找数据 */
        //public E get(int key)
        array.get(KEY);
        //public E get(int key, E valueIfKeyNotFound)
        //其中get(int key)也只是调用了 get(int key,E valueIfKeyNotFound),最后一个从传参的变量名就能看出,传入的是找不到的时候返回的值.get(int key)当找不到的时候,默认返回null。
        array.get(KEY, btn); // 如果这个key找不到value,那么就返回第二个参数。和default value一样
        
        // 查看第几个位置的键:
        //public int keyAt(int index)
        array.keyAt(1); // 如果找不到就返回-1
        
        // 查看第几个位置的值:
        //public E valueAt(int index)
        array.valueAt(1);
        // 查看值所在位置,没有的话返回-1:
        //public int indexOfValue(E value)
        array.indexOfValue(btn);
        
        SparseBooleanArray d;
    }
    }


测试代码四:

    public class FragmentPagerItemAdapter extends FragmentPagerAdapter {

    private final FragmentPagerItems mPages;
    private final SparseArrayCompat<WeakReference<Fragment>> mHolder;

    public FragmentPagerItemAdapter(FragmentManager fm, FragmentPagerItems pages) {
        super(fm);
        mPages = pages;
        mHolder = new SparseArrayCompat<>(pages.size());
    }

    @Override
    public int getCount() {
        return mPages.size();
    }

    @Override
    public Fragment getItem(int position) {
        return getPagerItem(position).instantiate(mPages.getContext(), position);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Object item = super.instantiateItem(container, position);
        if (item instanceof Fragment) {
            mHolder.put(position, new WeakReference<Fragment>((Fragment) item));
        }
        return item;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        mHolder.remove(position);
        super.destroyItem(container, position, object);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return getPagerItem(position).getTitle();
    }

    @Override
    public float getPageWidth(int position) {
        return super.getPageWidth(position);
    }

    public Fragment getPage(int position) {
        final WeakReference<Fragment> weakRefItem = mHolder.get(position);
        return (weakRefItem != null) ? weakRefItem.get() : null;
    }

    protected FragmentPagerItem getPagerItem(int position) {
        return mPages.get(position);
    }

    }

2015-11-19 20:29:12 sdlg2015 阅读数 411
  • Python入门视频教程

    购买课程后,请扫码进入学习群,获取唐宇迪老师答疑 Python入门基础教程:python教程旨在掌握python开发的入门基础用法与其核心操作,便于大家在短时间内可以使用python进行后续的工作与学习。课程内容包括Python环境搭建(Anaconda方式)、变量、List基础结构、List索引、循环结构、判断结构、字典结构、文件处理、函数基础等。

    18148 人正在学习 去看看 唐宇迪

Android进阶-分页与分批及XUtils的注解来代替findViewById

  • Point1 使用ListView完成分页与分批
    • 核心思想当然都是,获取数据,在ListView中展示
    • 涉及的数据库语句: SELECT * FROM INFOS LIMIT ? OFFSET ?
    • 但区别是:
      • 分页的数据是在改变的
      • 分批的数据是不断增加的

例如 List infos; infos中放有我们要展示的数据,
那么对于分页,我们可能会这样处理:

//响应用户改变页面的交互代码
    public void changePage(View view){
        /*处理页码,填充数据...*/
        changeData();
    }

    //当用户获取下一页数据, 这样更新infos中的数据, 这里infos是全局变量
    private void changeData() {
        infos = dao.findPart(curentPgeNumber, pageSize);
        handler.sendEmptyMessage(0);
    }
    //在Handler中,这样显示新的数据
    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
                lvPage.setAdapter(new MyPageAdapter());  
            }
        };
    };

但是对于分批,我们可能这样处理:

//监听ListView的滑动,以确定是否加载数据
    lvBull.setOnScrollListener(new OnScrollListener() {
            // 滚动状态发生变化调用的方法。
            // OnScrollListener.SCROLL_STATE_FLING 惯性滑动
            // OnScrollListener.SCROLL_STATE_TOUCH_SCROLL 触摸滑动
            // OnScrollListener.SCROLL_STATE_IDLE 静止
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                switch (scrollState) {
                case OnScrollListener.SCROLL_STATE_IDLE: // 静止状态
                    // 判断是否是最后一个条目。
                    int lastPosition = lv_callsms_safe.getLastVisiblePosition();
                    System.out.println("最后一个可见条目的位置:" + lastPosition);
                    if (lastPosition == infos.size() - 1) { //最后一个位置,是否为能展示的最后一条数据
                        /*.......*/
                        loadData();
                    }
                    break;
                }
            }

    private void loadData() {
        infos.addAll(dao.findPart2(startIndex, maxCount));//将新加载的数据添加到数据集合中
        handler.sendEmptyMessage(0);
    }

    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            adapter.notifyDataSetChanged(); //通知adapter,展示数据已经改变
        }
    };
  • Point2 使用XUtils的注解方式来代替findViewById

    1. 在onCreate()方法中,开启这个操作
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            /*....*/
            ViewUtils.inject(this);
        }
2. 在需要findViewById的控件上,添加@ViewInject注解,例如
        @ViewInject(R.id.btnAddBlackNumber)
        private Button btnAddBlackNumber;


2015-11-25 09:30:51 u012390990 阅读数 711
  • Python入门视频教程

    购买课程后,请扫码进入学习群,获取唐宇迪老师答疑 Python入门基础教程:python教程旨在掌握python开发的入门基础用法与其核心操作,便于大家在短时间内可以使用python进行后续的工作与学习。课程内容包括Python环境搭建(Anaconda方式)、变量、List基础结构、List索引、循环结构、判断结构、字典结构、文件处理、函数基础等。

    18148 人正在学习 去看看 唐宇迪

开发中我们会用到如下图的文本输入框


常规的办法是使用一张.9图片,如果没有切图的话,也可以使用layer-list进行绘制,如下:

<EditText 
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:background="@drawable/test_layer_list"
    android:inputType="text"
    />

test_layer_list.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
	<!-- 第一层 -->
    <item>
        <shape android:shape="rectangle" >
            <solid android:color="#47DBBD" />
        </shape>
    </item>
	<!-- 第二层-->
    <item android:bottom="5dp">
        <shape android:shape="rectangle" >
            <solid android:color="#ffffff" />
        </shape>
    </item> 
    
	<!-- 第三层 -->
    <item
        android:bottom="1dp"
        android:left="1dp"
        android:right="1dp">
        <shape android:shape="rectangle" >
            <solid android:color="#ffffff" />
        </shape>
    </item>
      
</layer-list>
如果只保留第一层,效果是这样的


只有一层绿色的背景

覆盖上第二层的效果


在绿色背景上覆盖了白色的背景,距离底部的距离是5dp

最后,加上第三层


ok,效果实现

2016-07-15 16:09:02 li12412414 阅读数 1528
  • Python入门视频教程

    购买课程后,请扫码进入学习群,获取唐宇迪老师答疑 Python入门基础教程:python教程旨在掌握python开发的入门基础用法与其核心操作,便于大家在短时间内可以使用python进行后续的工作与学习。课程内容包括Python环境搭建(Anaconda方式)、变量、List基础结构、List索引、循环结构、判断结构、字典结构、文件处理、函数基础等。

    18148 人正在学习 去看看 唐宇迪
我们平时在Android的开发当中,用得最多的应该是ListView了,但是,在Android5.0以后,Google推出了RecycleView这个类。这个类在平时的开发当中,可以显著地提高我们的效率。而且可以滑动。下面我们就来学习一个这个类。其中,cellData类定义了每一个Item中的数据。ViewHolder是我自定义的一个ViewHolder。list_cell.xml定义的是RecycleView中的每一项的试图。我们先来看一下俩个布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/tvContent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    <ImageView
        android:id="@+id/image"
        android:src="@drawable/ic_launcher"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <Button
        android:focusable="false"
        android:text="click me"
        android:id="@+id/btnclick"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


</LinearLayout>

content_main中的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="learnrv.lg.com.learnrv.MainActivity"
    tools:showIn="@layout/activity_main">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</RelativeLayout>

不过,在这个Demo中,其实这个主布局文件是没有用上的,没有任何意义。可以忽略。
CellData中的内容:
public class CellData {
    private int imageView;
    private String title;
    private String content;
    private Button btn;

    public CellData(String title, String content) {
        this.title=title;
        this.content=content;

    }

    public CellData(String title, String content, int imageView) {
        this(title, content);
        this.imageView=imageView;

    }

    public CellData(String title, String content, int imageView, Button btn) {
        this(title, content, imageView);
        this.btn=btn;
    }

    public int getImageView() {
        return imageView;
    }

    public String getContent() {
        return content;
    }

    public String getTitle() {
        return title;
    }


}

 /*定义一个对外公开的接口*/
public  interface  MyItemClickListener{
    public void onItemClick(View v, int position);

}

/*这里是自定义的ViewHolder,*/
    /*getPosition()viewHolder的内置的方法*/
public  class ViewHolder extends  RecyclerView.ViewHolder{
    private TextView tvTitle,tvContent;
    private ImageView imageView;
    private Button btn;
    private View root;
    /*考虑了父类的构造器*/
    public ViewHolder(View root) {
        super(root);
        this.root=root;
        tvTitle = (TextView) root.findViewById(R.id.tvTitle);
        tvContent = (TextView) root.findViewById(R.id.tvContent);
        imageView = (ImageView) root.findViewById(R.id.image);
        btn = (Button) root.findViewById(R.id.btnclick);
    }

    public View getRoot() {
        return root;
    }

    public TextView getTvContent() {
        return tvContent;
    }

    public TextView getTvTitle() {
        return tvTitle;
    }

    public ImageView getImageView() {
        return imageView;
    }

    public Button getBtn() {
        return btn;
    }

    public void setImageView(ImageView imageView) {
        this.imageView = imageView;
    }

    public void setTvContent(TextView tvContent) {
        this.tvContent = tvContent;
    }


    public void setTvTitle(TextView tvTitle) {
        this.tvTitle = tvTitle;
    }

    public void setBtn(Button btn) {
        this.btn = btn;
    }
}

/*这里是自定义的适配器*/
    /*在这个类中,我们还像ListView中的那样,为RecycleView中的每一项都增加了列表项的点击事件*/
        public class MyAdapter  extends RecyclerView.Adapter {
            private MyItemClickListener myItemClickListener=null;
            private CellData[] data = new CellData[]{new CellData("李果", "这个男孩真不错",R.drawable.ic_launcher), new CellData("新闻", "这个新闻真不错",R.drawable.ic_launcher),new CellData("李果", "这个男孩真不错",R.drawable.ic_launcher), new CellData("新闻", "这个新闻真不错",R.drawable.ic_launcher),new CellData("李果", "这个男孩真不错",R.drawable.ic_launcher), new CellData("新闻", "这个新闻真不错",R.drawable.ic_launcher),new CellData("李果", "这个男孩真不错",R.drawable.ic_launcher), new CellData("新闻", "这个新闻真不错",R.drawable.ic_launcher),new CellData("李果", "这个男孩真不错",R.drawable.ic_launcher), new CellData("新闻", "这个新闻真不错",R.drawable.ic_launcher),new CellData("李果", "这个男孩真不错",R.drawable.ic_launcher), new CellData("新闻", "这个新闻真不错",R.drawable.ic_launcher)};
            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                 /*这是一个布局解释器*/
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_cell, null);
                return new ViewHolder(view);
            }

    /*在这个方法中,可以初始化一些基本组件,这是要注意的*/
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        ViewHolder vh = (ViewHolder) holder;
        CellData cellData = data[position];
        vh.getTvTitle().setText(cellData.getTitle());
        vh.getTvContent().setText(cellData.getContent());
        vh.getImageView().setImageResource(cellData.getImageView());
/*如果在每一个的Item中,我们都增加了一个Button,那么为了监听Button的点击事件,那么我们应该怎么办呢
* 必须要注意的一点是,在布局中,在Button的布局中,我们可以将Buttonfocusable的属性设置为false就可以了*/
        vh.getBtn().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (myItemClickListener != null) {
                    myItemClickListener.onItemClick(v,position);
                    Log.v("Button--------->", "你点击的是" + position + "");
                }
            }
        });
        vh.getRoot().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (myItemClickListener != null) {
                    myItemClickListener.onItemClick(v, position);
                }
            }
        });
    }

    @Override
    public int getItemCount() {
        return data.length;
    }

    public void setMyItemClickListener(MyItemClickListener myItemClickListener) {
        this.myItemClickListener = myItemClickListener;
    }
}
package learnrv.lg.com.learnrv;
/*Recycle的优点是当数据比较多的时候,那么数据是可以拖动的。
* 而且它的效率比listView的效率要高*/
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;

/*Android中已经使用RecycleView来代替ListView的使用了。这是要注意的*/
public class MainActivity extends AppCompatActivity {
    private RecyclerView rv;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        rv = new RecyclerView(this);
        MyAdapter myAdapter = new MyAdapter();
        myAdapter.setMyItemClickListener(new  MyItemClickListener() {
            @Override
            public void onItemClick(View v, int position) {
                Toast.makeText(MainActivity.this, "你点击的是第" + position + "", Toast.LENGTH_SHORT).show();
            }
        });
        /*setLayoutManager有三个布局可以设计*/
        /*瀑布流,网格布局,线性布局*/
//        rv.setLayoutManager(new GridLayoutManager(this,3));
//        rv.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.HORIZONTAL));
        rv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        setContentView(rv);
        rv.setAdapter(myAdapter);
    }
}

最后显示的结果为:

更加详细内容的博客:点击打开链接;

没有更多推荐了,返回首页