Android 开发日常技术点笔记(一)

作者: 08eb053f790d | 来源:发表于2018-11-01 20:16 被阅读60次

经过一段时间的开发,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. 界面元素需要操作选中与否时,可以考虑在相关实体类中增加字段来表示该对象选中与否
App 中某页面的筛选条件

对应的实体类中,增加 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 的布局
  1. 覆写 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;
    }
}
  1. 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);
}
  1. 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() 方法,方便集合去重元素
  1. 有如下实体类:
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();
    }
}

在上面实体类中,我们假定了只要名字相同,就认为是同一个人

  1. 使用 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}]

可以看出名字为「刘备」的对象,只存储了第一个,可以使用此方法进行对象去重或者比较两个对象是否相等。

相关文章

网友评论

    本文标题:Android 开发日常技术点笔记(一)

    本文链接:https://www.haomeiwen.com/subject/sldibftx.html