-
Android Support v4:为兼顾1.6及以上的包
ViewPager、FragmentActivity
-
Android Support v7:为兼顾2.1及以上的包,v7依赖v4包
ActionBarActivity、ViewDragHelper、DrawerLayout
Android Support v13:为兼顾2.1及以上的包,一般是为了平板开发
TextView
-
<selector/>
正常颜色要放在最后面 - 通过drawable减少层级
Bitmap&Factory
在Android 2.3.3(API Level 10)以及之前,Bitmap的backing pixel 数据存储在native memory, 与Bitmap本身是分开的,Bitmap本身存储在dalvik heap 中。导致其pixel数据不能判断是否还需要使用,不能及时释放,容易引起OOM错误。 从Android 3.0(API 11)开始,pixel数据与Bitmap一起存储在Dalvik heap中。
-
图片宽高
BitmapFactory.decode(BitmapFactory.Option) // 使用参数解析图片以减少内存占用 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 第一次解析,只为获取options.outWidth/outHeight的值 bitmap = BitmapFactory.decodeFile(path, options); // 通过解析的宽、高计算合适的取样大小 if (sampleSize <= 0){sampleSize = 2;} // 解析时压缩(2的次方更快):1400*1400变为700*700 options.inPreferredConfig=Bitmap.Config.ARGB_4444; options.inJustDecodeBounds=false; // 第二次解析,获取真正的bitmap bitmap = BitmapFactory.decodeFile(path, options);
-
根据分辨率适配后的显示宽高(可以在onCreate的时候就获取到)
BitmapDrawable drawable = (BitmapDrawable) res.getDrawable(R.drawable.xx); int arrowHeight = drawable.getIntrinsicHeight(); int arrowWidth = drawable.getIntrinsicWidth();
-
Bitmap内存大小 =
宽度px
*高度px
*位深度所占大小
Bitmap.Config.ARGB_8888:每个A、R、G、B通道分别占4byte(8位256种颜色) 如700 * 700的图片占用(700*700*4)/1024/1024=1.87M
-
获取View快照
view.destroyDrawingCache(); view.setDrawingCacheEnabled(true); Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache()); view.setDrawingCacheEnabled(false);
ImageView
-
ImageView
的设置内容方法最终会生成一个mBitmapDrawable
对象,其内部持有真正的Bitmap
对象;注意mUri/mResource将在主线程解析bitmap,因此可能会引起阻塞setImageURI() setImageResource() setImageBitmap() setImageDrawable()
-
回收
protected void recycleImageView(ImageView imageView) { if (imageView != null) { Drawable drawable = imageView.getDrawable(); imageView.setImageDrawable(null); // 先切断关联 if (drawable != null) { // 获取图片 Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); } } } }
-
Bitmap
加载出来的大小(包括内存占用大小)和ImageView
显示的大小没有必然关系:显示的小未必占用内存小;且这两个不同大小的矩形矩形重叠在一起显示,需要不同的缩放策略private void initImageView() { mMatrix = new Matrix(); mScaleType = ScaleType.FIT_CENTER; } ScaleType.MATRIX, // Matrix ScaleType.FIT_XY, // Matrix.ScaleToFit.FILL ScaleType.FIT_START, // Matrix.ScaleToFit.START ScaleType.FIT_CENTER, // Matrix.ScaleToFit.CENTER ScaleType.FIT_END, // Matrix.ScaleToFit.END ScaleType.CENTER, // 底图bitmap不进行缩放,按原图居中显示,只是在draw bitmap之前将画布移动到左上角,对齐圆点而已 ScaleType.CENTER_CROP, // 把bitmap缩放后平移至居中;依照view的大边缩放(缩放比例较小) ScaleType.CENTER_INSIDE
ListView
AdapterView
中的addView()
、removeAllView()
都是不能使用的(抛异常)来保证所有的视图操作都是通过adapter来操作的-
设置底色为透明,优化性能
android:background="@android:color/transparent" android:cacheColorHint="@android:color/transparent" android:listSelector="@android:color/transparent"
setEmptyView()
; 需要empty view在当前布局中,可以结合ViewStub
item
高度最好使用确定值,因为ListView需要根据累计高度和总高度比较判断是否再调用getView()
android:duplicateParentState="true"
父控件响应点击事件,子View不响应点击事件,但是颜色要随着点击而发生变化多类别重写
getItemTypeCount()
; 决定了getView()
缓存几个converView-
listview是循环滑动的,所以没有所谓的
scrollY
,但可以通过监听计算得到mListView.setOnScrollListener(new OnScrollListener(){});
-
pointToPosition(downX,downY)
根据传入的XY判断点击的是哪个条目int clickPosition = pointToPosition(downX, downY); // 获取我们点击的item view View itemView = getChildAt(clickPosition - getFirstVisiblePosition());
复用
getView()
参数中的convertView;使用ViewHolder
减少findViewById次数-
addHeadView
-
addHeaderView(headView, null, false)
,false用来设置header是否可以被选择;可以多次调用,添加的View按照调用的顺序 - API19之前
addHeaderView()
必须放在listview.setadapter()
前面调用,API19之后可以随处调用。实质是对Adapter包装为HeaderViewListAdapter
- HeadView的点击事件在onItemClick中处理[?]
-
ViewPager
startUpdate()
destroyItem() // 先删除一个废弃的
instantiateItem() // 创建一个即将使用的
setPrimaryItem() // 多次调用,可以用来保存当前对象
finishUpdate() // 多次调用
saveState()
restoreState()
- ViewPager在切换的时候回重新定位焦点,导致重新布局[?]
Fragment
-
FragmentActivity
防止重复创建protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyFragment myFragment; if (savedInstanceState == null) { myFragment = MyFragment.newInstance(); // add fragment } // 或者 MyFragment myFragment = getSupportFragmentManager().findFragmentById(R.id.contentFrame); if (myFragment == null) { myFragment = MyFragment.newInstance(); // add fragment } }
-
Fragment
声明周期public class MyFragment extends BaseFragment { private Persenter mPersenter; private Listener mListener; public MyFragment() { setRetainInstance(true); } public static MyFragment newInstance() { return new MyFragment(); } public void onAttach(Activity activity) { super.onAttach(activity); if (activity instanceof Listener) { mListener = (Listener) activity; } } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.xxx, container, false); initView(); // ButterKnife.inject(this, view); return rootView; } public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (savedInstanceState == null) { this.loadUserDetails(); } } public void onDestroyView() { super.onDestroyView(); listview.setAdapter(null); ButterKnife.reset(this); } public void onDestroy() { super.onDestroy(); this.mPresenter.destroy(); // view = null; unsubscribe(); } public void onDetach() { super.onDetach(); mPersenter = null; } }
android:configChanges="orientation|screenSize"
- 如果不配置
Activity
和Fragment
将重新创建,setRetainInstance(true)可使Fragment不走onDestory方法 - 如果配置了
Activity
和Fragment
都不会重建