Android 開發日常技術點筆記(一)
經過一段時間的開發,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 的佈局
- 覆寫 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}]
可以看出名字為「劉備」的物件,只儲存了第一個,可以使用此方法進行物件去重或者比較兩個物件是否相等。