android控件之CheckBox

本文转自http://www.jb51.net/article/78961.htm

讲讲Checkbox的基本使用.在XML中定义

1
2
3
4
5
6
<? xml version = "1.0" encoding = "utf-8" ?>
< CheckBox xmlns:android = "http://schemas.android.com/apk/res/android"
  android:id = "@+id/cbx"
  android:layout_width = "wrap_content"
  android:layout_height = "wrap_content"
  android:checked = "false" />

在Activity中使用

1
2
3
4
5
6
7
CheckBox cbx = (CheckBox) findViewById(R.id.cbx);
cbx.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
   @Override
   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    //do something
   }
});

很简单.要注意的是,CheckBox本身是一个视图,是展示给用户看的,因此我们要用数据来控制它的展示.所以,我们的CheckBox在Activity中要这么写

1
2
3
4
5
6
7
8
9
10
11
12
13
boolean isChecked= false ;
CheckBox cbx = (CheckBox) findViewById(R.id.cbx);
cbx.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
   @Override
   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
     if (isChecked){
       //do something
     } else {
       //do something else
     }
   }
});
cbx.setChecked(isChecked);

这样,我们改变数据的时候,视图的状态就会跟着数据来做改变了.注意,监听器一定要这setChecked之前设置,这样才能体现出来数据来控制视图的展示.

单独用CheckBox很easy,接下来,复杂的情况来啦,CheckBox如何跟ListView/RecyclerView(以下简称LV/RV)配合使用.这就不能简单的考虑问题啦,要知道LV/RV中的视图个数跟数据集的里面的数据并不一致,真正的视图个数远小于数据集中数据项的个数.因为屏幕上在列表中的视图是可以复用的.由于LV/RV的复用机制,如果我们没有用数据来控制CheckBox状态的话,将会导致CheckBox的显示在列表中错乱.比方说你只对第一个Item中的CheckBox做了选中操作,当列表向上滚动的时候,你会发现,下面的Item中居然也会有被选中的.当然,问题的关键就在于要用数据来控制视图的显示.因此在getView/onBindViewHolder中,我们应该这么写.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
holder.cbx.setTag(item);
holder.cbx.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
   @Override
   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
     Item item =(Item) buttonView.getTag();
     if (isChecked){
       item.setCheckState( true );
       //do something
     } else {
       item.setCheckState( false );
       //do something else
     }
   }
});
cbx.setChecked(item.getCheckState());

这种方法基本正确,但是我们要额外的给每个数据项里面添加一个字段来记录状态,这代价就有点大了.一是不必这么做,二是这会导致本地数据结构跟服务端结构不一致.通常,列表中使用CheckBox的话,很明显是把选中的item给记录下来,可以这么理解,选中的状态是列表给的,而item本身应该是无状态的.那么,如果重构我们的代码呢,Android为我们提供了一种完美的数据结构来解决这个问题.你可以用SparseArray,也可以用SparseBooleanArray,我现在习惯使用SparseBooleanArray,ok,请看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
   SparseBooleanArray mCheckStates= new SparseBooleanArray();
   @Override
   public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
     //...
   }
   @Override
   public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
     holder.cbx.setTag(position);
     holder.cbx.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
       @Override
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
         int pos =( int )buttonView.getTag();
         if (isChecked){
           mCheckStates.put(pos, true );
           //do something
         } else {
           mCheckStates.delete(pos);
           //do something else
         }
       }
     });
     cbx.setChecked(mCheckStates.get(position, false ));
   }
   @Override
   public int getItemCount() {
     //...
   }
}

这样列表就能正常显示了,而且在你选中CheckBox的时候,会自动触发onCheckedChanged来对mCheckStates来进行更新.此时,如果你想用程序来选中某个item的时候,那么直接这样就行了.

1
2
mCheckStates.put(pos, true );
adapter.notifyDatasetChanged();

如果我们想要取出列表列中所有的数据项,有了SparseBooleanArray,

1
2
3
4
5
6
ArrayList<Item> selItems= new ArrayList<>();
for ( int i= 0 ;i < mCheckStates.size();i++){
   if (mCheckStates.valueAt(i)){
     selItems.add(allItems.get(mCheckStates.keyAt(i)));
   }
}

由于CheckBox这个控件太容易变了,为什么这么说呢,因为就算你把它设成disabled的话,它依然是可以点选的,它的onCheckedChanged依然会触发.那么我们该怎么办呢.程序员考虑问题呢,一般都是先想最笨的方法啦,既然onCheckedChanged依然会触发,那我就在里面把buttonView再设置成!isCheck的不就行了嘛.

1
2
3
4
5
6
7
holder.cbx.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
   @Override
   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
     buttonView.setChecked(!isChecked);
     //...
   }
});

但是这么写的话,就会调用buttonView的onCheckedChanged,其实buttonView就是外面的holder.cbx,这就会造成死循环.因此我们如果用cbx本身去改变状态的话,那么一定要加锁.

1
2
3
4
5
6
7
8
9
10
11
12
boolean lockState= false ;
holder.cbx.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
   @Override
   public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    if (lockState) return ;
    //不然cbx改变状态.
    lockState= true ;
     buttonView.setChecked(!isChecked);
     lockState= false ;
     //...
   }
});

对cbx加锁其实还是挺常用的,比方说在onCheckedChanged中,你要发一个请求,而请求的结果反过来会更新这个cbx的选中状态,你就必须要用lockState来直接改变cbx的状态了,以便于cbx的状态跟mCheckStates里面的是一致的.

mada mada,还有一种情况,如果在onCheckedChanged的时候,isChecked跟mCheckStates.get(pos)一致的话,这会导致什么情况呢.

1
2
3
4
5
6
7
8
9
10
11
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
  int pos =( int )buttonView.getTag();
   if (isChecked){
  mCheckStates.put(pos, true );
    //do something
  } else {
    mCheckStates.delete(pos);
    //do something else
  }
}

这就会让你的//do something做两次,这么做就是没有必要的啦,而且如果你的//do something是网络请求的话,这样就会导致更大问题.所以,我们有必要对这种情况做过滤.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
   if (lockState) return ;
   int pos =( int )buttonView.getTag();
   if (mCheckStates.get(pos, false ) == isChecked) return ;
   if (isChecked){
    mCheckStates.put(pos, true );
    //do something
   } else {
    mCheckStates.delete(pos);
    //do something else
   }
}

好啦,如果你能将CheckBox跟SparseBooleanArray联用,并且能考虑到加锁和过滤重选的话,那么说明你使用CheckBox的姿势摆正了.一个列表仅仅能让用户上滚下滑,那是最简单的使用,通常,由于列表项过多,产品会给列表项添加筛选的功能,而通常我们做筛选,会考虑到使用Spinner来做,但是,有用android自身提供的Spinner扩展性太差,而且长得丑,往往导致大家一怒之下,弃而不用.PopupWindow(介绍),我先介绍一下原理,首先给CheckBox设置setOnCheckedChangeListener,然后在onCheckedChanged里面,isChecked分支中弹出PopupWindow,!isChecked中,读取Popupwindow中的结果,用新的筛选条件来更新列表.ok,上代码:

MainActivity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class MainActivity extends AppCompatActivity {
 
   String[] filter_type_strs = { "音乐" , "书籍" , "电影" };
   CheckBox cbx;
   private boolean lockState= false ;
   int current_filter_type= 0 ;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
     super .onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     cbx = (CheckBox) findViewById(R.id.cbx);
 
     cbx.setText(filter_type_strs[current_filter_type]);
     cbx.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
       @Override
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
         if (lockState) return ;
         try {
           if (isChecked) {
             //此处传入了cbx做参数
             PopupWindow pw = new FilterLinePw(buttonView.getContext(), cbx, filter_type_strs);
             pw.showAsDropDown(cbx);
           } else {
             //此处的buttonView就是cbx
             Integer pos = (Integer) buttonView.getTag();
             if (pos == null || pos == - 1 ) return ;
             current_filter_type = pos;
 
             Toast.makeText(MainActivity. this , "搜索" +filter_type_strs[current_filter_type], Toast.LENGTH_SHORT).show();
           }
         } catch (NullPointerException e) {
           //以防万一
           lockState = true ;
           buttonView.setChecked(!isChecked);
           lockState = false ;
         }
       }
     });
 
   }
}

FilterLinePw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class FilterLinePw extends PopupWindow {
   RadioGroup radioGroup;
   CheckBox outCbx;
 
   //为动态生成radioButton生成id
   int [] rbtIds = { 0 , 1 , 2 };
 
   public FilterLinePw(Context context, CheckBox outCbx, String[] items) {
     super (ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
     View contentview = LayoutInflater.from(context).inflate(R.layout.filter_line_popupwindow, null );
     setContentView(contentview);
     setFocusable( true );
     setOutsideTouchable( true );
     this .outCbx = outCbx;
     contentview.setOnKeyListener( new View.OnKeyListener() {
       @Override
       public boolean onKey(View v, int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK) {
           dismiss();
           return true ;
         }
         return false ;
       }
     });
     contentview.setFocusable( true ); // 这个很重要
     contentview.setFocusableInTouchMode( true );
     contentview.setOnClickListener( new View.OnClickListener() {
       @Override
       public void onClick(View v) {
         dismiss();
       }
     });
 
     init(context, contentview,items);
 
   }
 
   private void init(Context context, View contentview, String[] items) {
     /**
      * 用传入的筛选条件初始化UI
      */
     radioGroup = (RadioGroup) contentview.findViewById(R.id.filter_layout);
     radioGroup.clearCheck();
     if (items == null ) return ;
     for ( int i = 0 ; i < items.length; i++) {
 
       RadioButton radioButton = (RadioButton) LayoutInflater.from(context).inflate(R.layout.line_popupwindow_rbt, null );
       radioButton.setId(rbtIds[i]);
       radioButton.setText(items[i]);
 
       radioGroup.addView(radioButton, - 1 , radioGroup.getLayoutParams());
 
       if (items[i].equals(outCbx.getText())) {
         outCbx.setTag(i);
         radioButton.setChecked( true );
       }
 
     }
     radioGroup.setOnCheckedChangeListener( new RadioGroup.OnCheckedChangeListener() {
       @Override
       public void onCheckedChanged(RadioGroup group, int checkedId) {
         dismiss();
       }
     });
   }
 
   //重点内容,重写dismiss();
   @Override
   public void dismiss() {
     if (outCbx != null && outCbx.isChecked()) {
       int id = radioGroup.getCheckedRadioButtonId();
       RadioButton rbt = (RadioButton) radioGroup.findViewById(id);
       Integer old_tag = (Integer) outCbx.getTag();
       if (old_tag == null ) {
         super .dismiss();
         return ;
       }
       if (old_tag != id) {
         outCbx.setTag(id);
         outCbx.setText(rbt.getText());
       } else {
         outCbx.setTag(- 1 );
       }
       //下面执行之后,会执行MainActivity中的onCheckedChanged里的否定分支
       outCbx.setChecked( false );
     }
     super .dismiss();
   }
}

效果图:



其实重点在PopupWindow里面,MainActivity的CheckBox作为参数传递到了 PopupWindow里.首先,用户点击MainActivity的CheckBox,接着会执行isChecked分支,这样PopupWindow就展示给了用户,这样用户操作的环境就到了PopupWindow里面,等用户选择好筛选条件后,PopupWindow就把筛选条件设给outCbx,然后改变outCbx状态,从而触发MainActivity中onCheckedChanged中的否定分支,此时展示的是一个Toast,实际应用中可以是一个网络请求.同时,由于PopupWindow的代码并没有阻塞操作,所以会接着执行下一句 super.dismiss(),这样你在MainActivity就不用担心PopupWindow的关闭问题啦.最后,在MainActivity中还加入了try-catch来以防万一,这种机制真是太神奇啦.这种机制把筛选操作从Activity中分离了出来,以后我们写筛选可以完全独立于Activity啦,随后我会把其他筛选的情况开源,

CheckBox是继承自TextView,很多时候,我们的CheckBox的button属性设置的图片都不大,这就导致点击CheckBox的区域也小,因此,我们需要用到TouchDelegate来扩大CheckBox的可点击区域上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class FrameLayoutCheckBox extends FrameLayout {
   CompoundButton cbx;
 
   public FrameLayoutCheckBox(Context context) {
     super (context);
   }
 
   public FrameLayoutCheckBox(Context context, AttributeSet attrs) {
     super (context, attrs);
   }
 
   public FrameLayoutCheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
     super (context, attrs, defStyleAttr);
   }
 
   private CheckBox findCheckBox(View view) {
     //无递归广度优先遍历寻找CheckBox - -!我只是想重温一下C
     ArrayList<View> views = new ArrayList<>();
     views.add(view);
     while (!views.isEmpty()) {
       View c = views.remove( 0 );
       if (c instanceof CheckBox) {
         return (CheckBox) c;
       } else if (c instanceof ViewGroup) {
         ViewGroup fa = (ViewGroup) c;
         for ( int i = 0 ; i < fa.getChildCount(); i++) {
           views.add(fa.getChildAt(i));
         }
       }
     }
     return null ;
   }
 
   @Override
   protected void onFinishInflate() {
     super .onFinishInflate();
     if (getChildCount() > 0 ) {
       View child = findCheckBox( this );
       if (child instanceof CompoundButton) cbx = (CompoundButton) child;
     }
   }
 
   @Override
   protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec) {
     super .onMeasure(widthMeasureSpec, heightMeasureSpec);
     if (cbx != null ) {
       Rect bounds = new Rect(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + getMeasuredWidth() + getPaddingRight(), getPaddingTop() + getMeasuredHeight() + getPaddingBottom());
       TouchDelegate delegate = new TouchDelegate(bounds, cbx);
       setTouchDelegate(delegate);
     }
   }
}

这个类可以当成FrameLayout,我们可以把CheckBox放里面,然后CheckBox的点击区域就是整个FrameLayout的区域啦.当然这个类也适用于RadioButton,但是你不能放多个CompoundButton在里面。


Android性能优化之谈谈SparseArray,SparseBooleanArray和SparseIntArray

相关内容转自http://www.lxway.com/42920216.htm

相信大家都明白,手机软件的开发不同于PC软件的开发,因为手机性能相对有限,内存也有限,所谓“寸土寸金”,可能稍有不慎,就会导致性能的明显降低。Android为了方便开发者,特意在android.util这个包中提供了几个提高效率的工具类,比如之前用过的LruCache类,这次我们来谈谈其他工具类,SparseArray,SparseBooleanArray和 SparseIntArray。


总体说,它们都是类似map这样key-value的存储方式,但是由于查找的算法不一样。因此效率也各不同。但要明白,没有说哪个一定是最好的。只有根据不同需求在不同场景去应用,才能获取较优的结果。


SparseArray

package android.util;

import com.android.internal.util.ArrayUtils;

/
 * SparseArrays 利用integer去管理object对象。不像一个正常的object对象数组,它能在索引数中快速的查找到所需的结果。(这
 * 句话是音译,原意是能在众多索引数中“撕开一个缺口”,为什么原文这么表达?下面会慢慢说清楚。)它比HashMap去通过Integer索引
 * 查找object对象时在内存上更具效率,不仅因为它避免了用来查找的自动“装箱”的keys,并且它的数据结构不依赖额外的对象去
 * 各个映射中查找匹配。
 * 
 * SparseArrays map integers to Objects.  Unlike a normal array of Objects,
 * there can be gaps in the indices.  It is intended to be more memory efficient
 * than using a HashMap to map Integers to Objects, both because it avoids
 * auto-boxing keys and its data structure doesn't rely on an extra entry object
 * for each mapping.
 *
 * 请注意,这个容器会保持它的映射关系在一个数组的数据结构中,通过二分检索法驱查找key。(这里我们终于知道,为何这个工具类中,
 * 提供的添加映射关系的操作中,key的类型必须是integer。因为二分检索法,将从中间“切开”,integer的数据类型是实现这种检索过程的保证。)
 * 
 * 如果保存大量的数据,这种数据结构是不适合的,换言之,SparseArray这个工具类并不应该用于存储大量的数据。这种情况下,它的效率
 * 通常比传统的HashMap更低,因为它的查找方法并且增加和移除操作(任意一个操作)都需要在数组中插入和删除(两个步骤才能实现)。
 * 
 * 如果存储的数据在几百个以内,它们的性能差异并不明显,低于50%。
 * 
 * (OK,那么光看Android官方的介绍我们就有初步结论了,大量的数据我们相对SparseArray会优先选择HashMap,如果数据在几百个这个数目,
 *  那么选择它们任意一个去实现区别不大,如果数量较少,就选择SparseArray去实现。 其实如果我们理解了二分法,就很容易了SparseArray的
 *  实现原理,以及SparseArray和HashMap它们之间的区别了。)
 * 
 * <p>Note that this container keeps its mappings in an array data structure,
 * using a binary search to find keys.  The implementation is not intended to be appropriate for
 * data structures
 * that may contain large numbers of items.  It is generally slower than a traditional
 * HashMap, since lookups require a binary search and adds and removes require inserting
 * and deleting entries in the array.  For containers holding up to hundreds of items,
 * the performance difference is not significant, less than 50%.</p>
 *
 *	
 * 为了提高性能,这个容器包含了一个实现最优的方法:当移除keys后为了立刻使它的数组紧密,它会“遗留”已经被移除(标记了要删除)的条目(entry) 。
 * 所被标记的条目(entry)(还未被当作垃圾回收掉前)可以被相同的key复用,也会在垃圾回收机制当作所有要回收的条目的一员被回收,从而使存储的数组更紧密。
 * 
 * (我们下面看源码就会发现remove()方法其实是调用delete()方法的。印证了上面这句话所说的这种优化方法。
 * 因为这样,能在每次移除元素后一直保持数组的数据结构是紧密不松散的。)
 * 
 * 垃圾回收的机制会在这些情况执行:数组需要扩充,或者映射表的大小被恢复,或者条目值被重新检索后恢复的时候。
 *	
 * <p>To help with performance, the container includes an optimization when removing
 * keys: instead of compacting its array immediately, it leaves the removed entry marked
 * as deleted.  The entry can then be re-used for the same key, or compacted later in
 * a single garbage collection step of all removed entries.  This garbage collection will
 * need to be performed at any time the array needs to be grown or the the map size or
 * entry values are retrieved.</p>
 *
 * 当调用keyAt(int)去获取某个位置的key的键的值,或者调用valueAt(int)去获取某个位置的值时,可能是通过迭代容器中的元素
 * 去实现的。
 *
 * <p>It is possible to iterate over the items in this container using
 * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
 * <code>keyAt(int)</code> with ascending values of the index will return the
 * keys in ascending order, or the values corresponding to the keys in ascending
 * order in the case of <code>valueAt(int)<code>.</p>
 */
public class SparseArray<E> implements Cloneable {
	//...
}



这里总结下几个重要的点:

1,SparseArray的原理是二分检索法,也因此key的类型都是整型。

2,(HashMap和SparseArray比较)当存储大量数据(起码上千个)的时候,优先选择HashMap。如果只有几百个,用哪个区别不大。如果数量不多,优先选择SparseArray。

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

接着将里面的主要方法列出来:

private int index = 1;
	private String value = "value";
	
	public void testSparseArray()
	{
		//创建一个SparseArray对象
		SparseArray<String> sparseArray = new SparseArray<String>();
		
		//向sparseArray存入元素value,key为index
		sparseArray.put(index, value);
		
		//这个方法本质也是利用put(key, value)去存入数据
		sparseArray.append(index, value);
		
		
		sparseArray.indexOfKey(index);
		//查找value所在的位置,如果不存在,则返回-1
		sparseArray.indexOfValue(value);
		
		
		
		//更新某个key的值
		sparseArray.setValueAt(index, value);
		
		
		
		//获取index所对应的值,没有则返回null
		sparseArray.get(index);
		//获取index所对应的值,没有则返回自定义的默认值"default-value"
		sparseArray.get(index,"default-value");
		
		
		
		//删除index对应的元素
		sparseArray.delete(index);
		//移除,本质也是调用delete(int)方法
		sparseArray.remove(index);
		
		
		
		//清空所有数据
		sparseArray.clear();
		
	}


SparseBooleanArray和SparseIntArray

SparseBooleanArray和SparseIntArray,其实看名字也知道,它们跟SparseArray极其类似,只是存储类型加以限制了。SparseBooleanArray只能存储boolean值,而SparseIntArray只能存储integer类型的值。它们也同样实现了Cloneable接口,可以直接调用clone方法,也同样是以二分法为依据。而其他的主要方法也是一样的。下面以SparseBooleanArray为简单例子写出主要的方法,从方法看出,两者和SparseArray的确是灰常类似的。SparseIntArray的代码就不再贴出来了,因为都一样的。我们在使用的过程中举一反三,会用一个,其他2个也就会用了呢。

public void testSparseBooleanArray()
	{
		
//		SparseBooleanArray sparseBooleanArray = new SparseBooleanArray();
		//这种创建方式可以设置容器的大小
		SparseBooleanArray sparseBooleanArray = new SparseBooleanArray(5);
		
		
		//存入数据,同样有两种方法
		sparseBooleanArray.put(int, boolean);
		
		sparseBooleanArray.append(int, boolean);
		
		//根据key获取对应的boolean值,没有则返回false
		sparseBooleanArray.get(key);
		//跟上面类似,valueIfKeyNotFound是自定义的假设不存在则返回的默认值
		sparseBooleanArray.get(key, valueIfKeyNotFound);
		
		//获取第5个位置的键值
		sparseBooleanArray.keyAt(5);
		//获取第5个元素的值
		sparseBooleanArray.valueAt(5);
		
		//删除某个key的元素
		sparseBooleanArray.delete(key);
		//清除所有
		sparseBooleanArray.clear();
		
	}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值