好像很久没有发博客了,最近也是很忙(借口!),有很多需要记录的知识没来得及写,此次动笔,因为这个坑也是挺折磨人。
起因:在ActivityA 和ActivityB中都有一个Button 这两个按钮,都使用了一个drawable对象,当在ActivityA改变drawable的样式时,ActivityB随之改变。
activitya.xml
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:background="@drawable/button"
android:id="@+id/bt1"/>
<Button
android:layout_width="wrap_content"
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:text="点击改变Button背景样式"
android:id="@+id/set_button"/>
<Button
android:layout_width="wrap_content"
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:text="启动ActivityB"
android:id="@+id/start_activity_button"
android:visibility="gone"/>
MainActivity.java
public class MainActivity extends AppCompatActivity {
Button bug_button;
Button set_button;
Button start_activity_button;
int bug_button_style;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init(this);
}
private void init(final Context context) {
bug_button = findViewById(R.id.bt1);
set_button = findViewById(R.id.set_button);
start_activity_button = findViewById(R.id.start_activity_button);
set_button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View p1) {
if(bug_button_style == 0){
bug_button_style = 1;
bug_button.setBackgroundDrawable(Util.createButton(context,0xFF636867));
}else{
bug_button_style = 0;
bug_button.setBackgroundDrawable(Util.createButton(context,0xFF588BC0));
}
bug_buttobu.per
}
});
final Intent intent = new Intent(this, ActivityB.class);
start_activity_button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View p1) {
context. startActivity(intent,null);
}
});
}
工具类
public class Util {
public static LayerDrawable createButton(Context context,int color){
LayerDrawable drawable = (LayerDrawable) context.getDrawable(R.drawable.button);
((GradientDrawable)drawable.getDrawable(0)).setColor(color);
return drawable;
}
}
最后drawable文件 button.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--rectangle矩形-->
<!--圆角-->
<size
android:width="35dp"
android:height="35dp"></size>
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp"
android:bottomRightRadius="10dp"
android:bottomLeftRadius="10dp"
/>
<solid android:color="@color/button_default_bg"></solid>
<!--大小-->
<!--描边-->
<stroke
android:width="5dp"
android:color="@color/button_disable_bg" />
</shape>
</item>
</layer-list>
大概就是这样的,ActivityB没有东西 就不贴了。
然后运行效果跟前面说的一致,后面查阅才发现Drawable是有缓存的,解决办法同样很简单。
工具类中getDrawable之后使用mutate
context.getDrawable(R.drawable.button).mutate();
发现这个是因为在一个项目中,我使用了两个RecyclerView(先不考虑这样使用是否有弊端) :
第一个用于显示数据
第二个显示数据并进行修改
但两个适配器引用的数据是相等的(第二个RecyclerView的数据从第一个拿),然后神奇的事情发生了, 再第二个RecyclerView中修改的数据即使没有保存,也能在第一个RecyclerView生效。
写了一个Demo如图:
很诧异,因为有了上一个因为drawable缓存导致的问题,所以起初认为也是drawable的问题,直到我甚至替换了不一样的Drawable,还把第二个RecyclerView改成ListView,但都无法解决,所以问题并不在Android部分,并且两个适配器相同的东西也只有一个List集合而已,那是不是这个List集合也有缓存呢?(留下了基础不扎实的眼泪)
public class Main {
public static void main(String[] args) {
List<String> oldList = new ArrayList<String>();
for(int i = 0;i<5;i++){
oldList.add("小明的同学" + i);
}
List<String> newList = oldList;
newList.set(3,"小明的朋友");
System.out.println(oldList.toString());
System.out.println(newList.toString());
}
}
输出结果是:
[小明的同学0, 小明的同学1, 小明的同学2, 小明的朋友, 小明的同学4]
[小明的同学0, 小明的同学1, 小明的同学2, 小明的朋友, 小明的同学4]
可以看到两个List的数据都变了,可是我明明只改了newList,其实是因为我只对List进行了 浅拷贝。
浅拷贝是对前一个数据的”引用传递”,像**ListA = ListB; **
**ListA.addAll(ListB); **
两个都是浅拷贝。
网上的深拷贝大概两个办法,第一个是把原List序列化
public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
@SuppressWarnings("unchecked")
List<T> dest = (List<T>) in.readObject();
return dest;
}
第二种则是子集对象实现Cloneable接口 ,并重写clone ,然后我稍微封装了一下。
public static <T extends DeepClone> List<T> deepClone(List<T> src) {
List<T> list = new ArrayList<>();
for(T obj : src){
list.add((T)obj.clone());
}
return list;
}
public static class DeepClone implements Cloneable{
@Override
protected Object clone() {
Test test = null;
try {
test = (Test) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return test;
}
}
让对象继承这个DeepClone 然后使用deepClone克隆List就行了😁。