2019秋招必備面試題彙總+阿里P6P7安卓進階資料分享
相信Android開發,特別是電商項目開發,使用RecyclerView、ListView、GridView是正常不過的了。一個項目下來,基本就是一直在寫Adapter。剛開始寫Adapter以爲沒什麼,無非就是ListView的繼承BaseAdapter複寫幾個方法,getView裏面使用ViewHolder模式;RecyclerView的就繼承 RecyclerView.Adapter,複寫onCreateViewHolder、onBindViewHolder而後實現便完事。但當我寫到10遍、100遍甚至更多的時候,我就不想寫了,反正都是這種寫法,也沒什麼新的套路。因而我就想寫一個RecyclerView、ListView、GridView通用的Adapter。git
代碼沒什麼難度能夠隨便看看就好。github
public class ListViewAdapter extends BaseAdapter { private LayoutInflater mInflater; private Context mContext; private List<String> mDatas; private int mLayoutId; public ListViewAdapter(Context context, List<String> mDatas,int layoutId) { mInflater = LayoutInflater.from(context); this.mContext = context; this.mDatas = mDatas; this.mLayoutId = layoutId; } @Override public int getCount() { return mDatas.size(); } @Override public Object getItem(int position) { return mDatas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { convertView = mInflater.inflate(R.mLayoutId, parent, false); viewHolder = new ViewHolder(); viewHolder.mTextView = (TextView) convertView .findViewById(R.id.id_tv); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.mTextView.setText(mDatas.get(position)); return convertView; } private final class ViewHolder { TextView mTextView; } } private class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.Holder> { private LayoutInflater mInflater; private Context mContext; private List<String> mData; private int mLayoutId; public RecyclerAdapter(Context context, List<String> data, int layoutId) { mInflater = LayoutInflater.from(context); this.mContext = context; this.mData = data; this.mLayoutId = layoutId; } @Override public Holder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(mLayoutId, parent, false); return new Holder(view); } @Override public void onBindViewHolder(Holder holder, int position) { holder.tv.setText(mData.get(position)); } @Override public int getItemCount() { return mData.size(); } class Holder extends RecyclerView.ViewHolder { public TextView tv; public Holder(View itemView) { super(itemView); tv = itemView.findViewById(R.id.tv); } } }
1. 要顯示的條目個數
2. 要顯示和條目對應的類型
3. ListView、RecyclerView中,總共有多少個條目類型
4. 根據不一樣的條目類型加載不一樣的View
5. ListView複用條目convertView,RecyclerView自帶ViewHoler複用 </pre>面試
因爲要通用RecyclerView、ListView、GridView只能將RecyclerView.Adapter和ListAdapter,SpinnerAdapter
這些都給實現了。裏面也沒多少個方法,其實也是很簡單。至於一些方法的實現我考貝BaseAdapter的實現,
你們能夠去看看BaseAdapter的源碼。ide
public class BaseAdapter extends RecyclerView.Adapter implements ListAdapter, SpinnerAdapter { private final DataSetObservable mDataSetObservable = new DataSetObservable(); // RecyclerView======================================================================== @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return null; } // RecyclerView @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } // RecyclerView @Override public int getItemCount() { return 0; } // RecyclerView======================================================================== // ListView======================================================================== @Override public boolean areAllItemsEnabled() { return true; } @Override public boolean isEnabled(int position) { return true; } @Override public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } @Override public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } public void notifyListDataSetChanged() { mDataSetObservable.notifyChanged(); } @Override public Object getItem(int position) { return null; } @Override public View getView(int position, View convertView, ViewGroup parent) { return null; } @Override public int getViewTypeCount() { return 1; } @Override public int getItemViewType(int position) { return 0; } @Override public int getCount() { return 0; } @Override public boolean isEmpty() { return getCount() == 0; } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { return getView(position, convertView, parent); } }
public interface QuickMultiSupport<T> { /** * 獲取多條目View類型的數量 */ int getViewTypeCount(); /** * 根據數據,獲取多條目佈局ID */ int getLayoutId(T data); /** * 根據數據,獲取多條目的ItemViewType */ int getItemViewType(T data); /** * 是否合併條目-->>使用RecyclerView時,若是無效,請用原生的RecyclerView */ boolean isSpan(T data);
因爲要同時適配RecyclerView、ListView、GridView,也就等於把兩個Adapter的實現放在一個類裏面
因此代碼有點多,但代碼我已分開,很容易看。
還有數據都複製出來的,條目的增刪改查都在Adapter裏面。佈局
/** * RecyclerView、ListView、GridView通用的適配器 */ public abstract class QuickAdapter<T> extends BaseAdapter { private Context mContext; private List<T> mData; private int mLayoutId; private QuickMultiSupport<T> mSupport; private boolean isRecycler; private int mPosition; public QuickAdapter(Context context, List<T> data, int layoutId) { this.mContext = context; this.mData = data == null ? new ArrayList<T>() : new ArrayList<T>(data); this.mLayoutId = layoutId; } public QuickAdapter(Context context, List<T> data, QuickMultiSupport<T> support) { this(context, data, 0); this.mSupport = support; } @Override public int getCount() { return mData.size(); } @Override public T getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { QuickViewHolder holder; if (convertView == null) { int layoutId = mLayoutId; // 多條目的 if (mSupport != null) { layoutId = mSupport.getLayoutId(mData.get(position)); } // 建立ViewHolder holder = createListHolder(parent, layoutId); } else { holder = (QuickViewHolder) convertView.getTag(); // 防止失誤,還要判斷 if (mSupport != null) { int layoutId = mSupport.getLayoutId(mData.get(position)); // 若是佈局ID不同,又從新建立 if (layoutId != holder.getLayoutId()) { // 建立ViewHolder holder = createListHolder(parent, layoutId); } } } // 綁定View的數據 convert(holder, mData.get(position), position); return holder.itemView; } /** * 建立ListView的Holer */ @NonNull private QuickViewHolder createListHolder(ViewGroup parent, int layoutId) { QuickViewHolder holder; View itemView = LayoutInflater.from(mContext).inflate(layoutId, parent, false); holder = new QuickViewHolder(itemView, layoutId); itemView.setTag(holder); return holder; } /** * ViewType的數量 */ @Override public int getViewTypeCount() { // 多條目的 if (mSupport != null) { return mSupport.getViewTypeCount() + super.getViewTypeCount(); } return super.getViewTypeCount(); } /** * 這個方法是共用的 */ @Override public int getItemViewType(int position) { mPosition = position; // 多條目的 if (mSupport != null) { return mSupport.getItemViewType(mData.get(position)); } return super.getItemViewType(position); } // RecyclerView================================================================================= @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { isRecycler = true; // 若是是多條目,viewType就是佈局ID View view; if (mSupport != null) { int layoutId = mSupport.getLayoutId(mData.get(mPosition)); view = LayoutInflater.from(mContext).inflate(layoutId, parent, false); } else { view = LayoutInflater.from(mContext).inflate(mLayoutId, parent, false); } QuickViewHolder holder = new QuickViewHolder(view); return holder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof QuickViewHolder) { convert((QuickViewHolder) holder, mData.get(position), position); } } @Override public int getItemCount() { return mData.size(); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { if (mSupport == null || recyclerView == null) { return; } RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup(); // 若是設置合併單元格就佔用SpanCount那個多個位置 gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { if (mSupport.isSpan(mData.get(position))) { return gridLayoutManager.getSpanCount(); } else if (spanSizeLookup != null) { return spanSizeLookup.getSpanSize(position); } return 1; } }); gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount()); } } @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { if (mSupport == null) { return; } int position = holder.getLayoutPosition(); // 若是設置合併單元格 if (mSupport.isSpan(mData.get(position))) { ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) { StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; p.setFullSpan(true); } } } // RecyclerView================================================================================= /** * 綁定View的數據 */ protected abstract void convert(QuickViewHolder holder, T item, int position); //==========================================數據相關================================================ public void add(T elem) { mData.add(elem); notifyData(); } public void addAll(List<T> data) { mData.addAll(data); notifyData(); } public void addFirst(T elem) { mData.add(0, elem); notifyData(); } public void set(T oldElem, T newElem) { set(mData.indexOf(oldElem), newElem); notifyData(); } public void set(int index, T elem) { mData.set(index, elem); notify(); } public void remove(T elem) { mData.remove(elem); notifyData(); } public void remove(int index) { mData.remove(index); notifyData(); } public void replaceAll(List<T> elem) { mData.clear(); mData.addAll(elem); notifyData(); } /** * 清除 */ public void clear() { mData.clear(); notifyData(); } private void notifyData() { if (isRecycler) { notifyDataSetChanged(); } else { notifyListDataSetChanged(); } } public List<T> getData() { return mData; } }
ViewHolder最主要就是實現平時經常使用的方法,好比:點擊事件、長按事件、給TextView設置內容等等
若是不夠,實際開發能夠本身添加。測試
public class QuickViewHolder extends RecyclerView.ViewHolder { private SparseArray<WeakReference<View>> mViews; private int mLayoutId; public QuickViewHolder(View itemView) { this(itemView, -1); } public QuickViewHolder(View itemView, int layoutId) { super(itemView); mViews = new SparseArray<>(); this.mLayoutId = layoutId; } public int getLayoutId() { return mLayoutId; } /** * 設置條目的點擊事件 */ public QuickViewHolder setOnClickListener(View.OnClickListener listener) { itemView.setOnClickListener(listener); return this; } /** * 設置條目的長按事件 */ public QuickViewHolder setOnLongClickListener(View.OnLongClickListener listener) { itemView.setOnLongClickListener(listener); return this; } /** * 設置View的點擊事件 * * @return */ public QuickViewHolder setOnClickListener(int viewId, View.OnClickListener listener) { View view = getView(viewId); if (view != null) { view.setOnClickListener(listener); } return this; } /** * 獲取條目的View */ public View getView() { return itemView; } /** * 根據ID獲取條目裏面的View */ public <T extends View> T getView(int viewId) { WeakReference<View> viewWeakReference = mViews.get(viewId); View view = null; if (viewWeakReference == null) { view = itemView.findViewById(viewId); if (view != null) { mViews.put(viewId, new WeakReference<>(view)); } } else { view = viewWeakReference.get(); } return (T) view; } public QuickViewHolder setText(int viewId, CharSequence text) { TextView tv = getView(viewId); if (tv != null && !TextUtils.isEmpty(text)) { tv.setText(text); } return this; } /** * 設置圖片背景顏色 */ public QuickViewHolder setTextColor(int viewId, int color) { TextView view = getView(viewId); if (view != null) { view.setTextColor(color); } return this; } /** * 設置控件是否可見 */ public QuickViewHolder setVisible(int viewId, int visible) { View view = getView(viewId); view.setVisibility(visible); return this; } /** * 設置控件選中 */ public QuickViewHolder setChecked(int viewId, boolean checked) { Checkable view = getView(viewId); view.setChecked(checked); return this; } /** * 設置控件背景 */ public QuickViewHolder setBackgroundRes(int viewId, int backgroundRes) { View view = getView(viewId); view.setBackgroundResource(backgroundRes); return this; } /** * 設置圖片 */ public QuickViewHolder setImageResource(int viewId, int imageResId) { ImageView imageView = getView(viewId); imageView.setImageResource(imageResId); return this; } /** * 設置圖片 */ public QuickViewHolder setImageBitmap(int viewId, Bitmap bitmap) { ImageView imageView = getView(viewId); imageView.setImageBitmap(bitmap); return this; } }
我只寫了多條目的測試使用,對於一種類型的寫法更爲簡單,我就不寫了。ui
public class MainActivity extends AppCompatActivity { private List<IViewType> mData = new ArrayList<>(); private QuickMultiSupport<IViewType> mQuickSupport; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initViews(); } /** * 多條目的ViewType */ public interface IViewType { int getItemViewType(); } private void initData() { for (int i = 0; i < 199; i++) { if (i % 10 == 0) { MultiBean bean = new MultiBean(); bean.name = "mData--------" + i; mData.add(bean); } else { MultiBean1 bean = new MultiBean1(); bean.name = "mData--------" + i; mData.add(bean); } } // 多條目支持 mQuickSupport = new QuickMultiSupport<IViewType>() { // 條目總共兩種類型 @Override public int getViewTypeCount() { return 2; } // 根據不用的JavaBean返回不一樣的佈局 @Override public int getLayoutId(IViewType data) { if (data instanceof MultiBean) { return R.layout.item_list1; } return R.layout.item_list; } @Override public int getItemViewType(IViewType data) { return data.getItemViewType(); } @Override public boolean isSpan(IViewType data) { // 是否佔用一個條目,針對RecyclerView if (data instanceof MultiBean) { return true; } return false; } }; } private void initViews() { ListView listView = findViewById(R.id.list_view); RecyclerView recyclerView = findViewById(R.id.recycler_view); // ListView設置Adapter listView.setAdapter(new CommAdapter(this, mData, mQuickSupport)); // RecyclerView設置Adapter recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); recyclerView.setAdapter(new CommAdapter(this, mData, mQuickSupport)); } class CommAdapter extends QuickAdapter<IViewType> { public CommAdapter(Context context, List<IViewType> data, int layoutId) { super(context, data, layoutId); } public CommAdapter(Context context, List<IViewType> data, QuickMultiSupport<IViewType> support) { super(context, data, support); } @Override protected void convert(QuickViewHolder holder, IViewType item, final int position) { holder.setText(R.id.tv, item.toString()); holder.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 點擊移除當前條目 remove(position); } }); } } }
至此不管是RecyclerView仍是ListView終於只用一個Adapter,是否是很開心
項目運行的實際效果:左邊是ListView,右邊是RecyclerView。this
源碼地址:
https://github.com/wenkency/C...
2019秋招必備面試題彙總+阿里P6P7安卓進階資料分享spa