Android 开发日常技术点笔记(一)
2018-11-01 本文已影响60人
08eb053f790d
经过一段时间的开发,App 二期功能大概完成,在开发过程中遇到几个技术点需要注意,在此整理记录下来。主要包括系统 API 调用,功能实现和控件使用。
1. For-Each 循环中移除元素时需要使用 Iterator 迭代器进行操作,不能直接使用集合操作
在开发中,经常需要操作集合(List)中的元素,要对其中的某个元素进行操作时,往往会遍历集合,获取指定的元素进行操作,对于一般字段值的修改,这样做是没有问题的,但是当有匹配条件的元素需要从集合中移除时,这样就会出错。
错误代码如下:
User user1 = new User("刘备", "男", 55);
User user2 = new User("曹操", "男", 50);
User user3 = new User("孙权", "男", 52);
User user4 = new User("小乔", "女", 25);
userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
//移除指定元素
for (User user : userList) {
if (user.getName().equals("曹操")) {
userList.remove(user);
}
}
Log.d("SUN", userList.toString());
......
运行结果抛出如下异常:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at com.helper.mlnglobal.mlnhelper.MainActivity.doAction(MainActivity.java:57)
at com.helper.mlnglobal.mlnhelper.MainActivity.access$000(MainActivity.java:23)
at com.helper.mlnglobal.mlnhelper.MainActivity$1.onClick(MainActivity.java:36)
at android.view.View.performClick(View.java:6291)
at android.view.View$PerformClick.run(View.java:24931)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:101)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7425)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)
正确代码如下:
//使用 Iterator 移除数据
Iterator<User> userIterator = userList.iterator();
while (userIterator.hasNext()) {
User user = userIterator.next();
if (user.getName().equals("曹操")) {
userIterator.remove();
}
}
Log.d("SUN", userList.toString());
......
2. 界面元素需要操作选中与否时,可以考虑在相关实体类中增加字段来表示该对象选中与否

对应的实体类中,增加 isSelect 字段标志选中的筛选条件
private String text;
//标志选中与否,可动态改变
private boolean isSelect;
private String hintName;
......
3. PopupWindow 控件的实际使用
使用 PopupWindow 可以生成一个弹窗,根据需求自定义弹窗的内容布局,并指定弹窗的位置,实现各种自定义效果。
//设置布局文件
View moreView = LayoutInflater.from(mContext).inflate(R.layout.project_more_search_layout, null);
PopupWindow morePopupWindow = new PopupWindow(moreView);
//背景
ColorDrawable cd = new ColorDrawable(0xb0000000);
morePopupWindow.setBackgroundDrawable(cd);
//宽高
morePopupWindow.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
morePopupWindow.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
//获取焦点
morePopupWindow.setFocusable(true);
//点击窗口外可消失
morePopupWindow.setOutsideTouchable(true);
//指定位置
morePopupWindow.showAsDropDown(rlHouseCountry);
......
4. 类似省市的「二级列表菜单」可以通过使用两个 ListView (或者 RecyclerView)来实现
5. 使用 RecyclerView 可以打造不同类型 Item 的布局
- 覆写 getItemViewType(int position) 方法,指定不同的布局类型 viewType
@Override
public int getItemViewType(int position) {
if (position == 0) {
//开发商详情的信息展示模块
return TYPE_FIRST;
} else if (position <= contactsBeanList.size()) {
//联系人模块
return TYPE_SECOND;
} else if (position <= contactsBeanList.size() + 1) {
//查看更多和收起模块
return TYPE_THIRD;
} else if (position <= contactsBeanList.size() + 1 + 1) {
//历史信息上面的分割模块
return TYPE_FOURTH;
} else if (position <= contactsBeanList.size() + 1 + 1 + historyBeanList.size()) {
//历史信息
return TYPE_FIFTH;
} else if (position <= contactsBeanList.size() + 1 + 1 + historyBeanList.size() + 1) {
//房产模块上面的分割模块
return TYPE_SIXTH;
} else { //开发商详情界面的房产项目列表
return TYPE_SEVENTH;
}
}
- 在 onCreateViewHolder(ViewGroup parent, int viewType) 方法中根据 viewType 返回不同的 ViewHolder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_FIRST) {
View item_view = LayoutInflater.from(mContext).inflate(R.layout.building_developer_detail_first_item, parent, false);
return new MyFirstViewHolder(item_view);
} else if (viewType == TYPE_SECOND) {
View item_view = LayoutInflater.from(mContext).inflate(R.layout.building_developer_detail_second_item, parent, false);
return new ContactViewHolder(item_view);
} else if (viewType == TYPE_THIRD) {
View item_view = LayoutInflater.from(mContext).inflate(R.layout.building_developer_detail_see_more_item, parent, false);
return new SeeMoreViewHolder(item_view);
} else if (viewType == TYPE_FOURTH) {
View item_view = LayoutInflater.from(mContext).inflate(R.layout.building_developer_detail_third_item, parent, false);
return new DividerViewHolder(item_view);
} else if (viewType == TYPE_FIFTH) {
View item_view = LayoutInflater.from(mContext).inflate(R.layout.building_developer_detail_fourth_item, parent, false);
return new HistoryStepViewHolder(item_view);
} else if (viewType == TYPE_SIXTH) {
View item_view = LayoutInflater.from(mContext).inflate(R.layout.building_developer_detail_third_item, parent, false);
return new ProjectDividerViewHolder(item_view);
}
View item_view = LayoutInflater.from(mContext).inflate(R.layout.item_hotsale_house, parent, false);
return new HouseDetailViewHolder(item_view);
}
- 在 onBindViewHolder(RecyclerView.ViewHolder holder, int position) 中根据不同的 ViewHolder 返回不同的数据
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// 开发商基本信息
if (holder instanceof MyFirstViewHolder) {
......
// 联系人
} else if (holder instanceof ContactViewHolder) {
......
//查看更多
} else if (holder instanceof SeeMoreViewHolder) {
......
// 历史信息头部布局
} else if (holder instanceof DividerViewHolder) {
......
// 数据化历史信息
} else if (holder instanceof HistoryStepViewHolder) {
......
// 项目分割线
} else if (holder instanceof ProjectDividerViewHolder) {
......
// 该开发商下面的房产项目信息
} else if (holder instanceof HouseDetailViewHolder) {
......
}
}
6. 重写对象的 equals(Object obj) 和 hashCode() 方法,方便集合去重元素
- 有如下实体类:
public class User {
private String name; //名字
private String sex; //性别
private int age; //年龄
public User(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
User user = (User) o;
//此处假设名字相同就是一个人
return this.name.equals(user.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}
在上面实体类中,我们假定了只要名字相同,就认为是同一个人
- 使用 HashSet 存储对象:
User user1 = new User("刘备", "男", 55);
User user2 = new User("曹操", "男", 50);
User user3 = new User("刘备", "男", 52);
User user4 = new User("小乔", "女", 25);
//使用 HashSet 存储对象
userHashSet = new HashSet<>();
userHashSet.add(user1);
userHashSet.add(user2);
userHashSet.add(user3);
userHashSet.add(user4);
打印数据:
Log.d("SUN", userHashSet.toString());
打印结果是:
D/SUN: [User{name='刘备', sex='男', age=55}, User{name='曹操', sex='男', age=50}, User{name='小乔', sex='女', age=25}]
可以看出名字为「刘备」的对象,只存储了第一个,可以使用此方法进行对象去重或者比较两个对象是否相等。