Android Dev Tips

  1. onLongClick() 返回true时会自动震动
  1. getLocationInWindow 不算notification bar

getLocationOnScreen 整个屏幕

3.

fillBefore是指动画结束时画面停留在此动画的第一帧; 默认值为true

fillAfter是指动画结束是画面停留在此动画的最后一帧。默认值为false

1,FillEnable = false 时,FillBefore 和FillAfter的值将被忽略,此时FillEnable=Flase时和FillBefore =true且FillAfter=true,且FillEnabled=true等价,也就是开始结束都会被fill坑爹。。。

2,FillEnable = true时,FillBefore = true,FillAfter = false

只在第一帧fill

3,FillEnable = true时,FillBefore = false,FillAfter=true

只在最后一帧fill

4,FillEnable = true时,FillBefore = false,FillAfter=false

这个控制也比较坑爹,从变量名理解以为只要FillEnable=false就好,其它当FillEnable=false时又回到第1种情况太坑爹了。。

4、

在Manifest中的Activity里添加:android:windowSoftInputMode="adjustResize"

可以使得键盘输入时布局重新变化。

5、

测量显示区域,windowRect为去掉statusBar 和输入法的区域

Rect windowRect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(windowRect);

  1. ListView.getChildAt(int)

child是指所有可见的item(包括部分可见的,以及header和footer,可通过getHeaderCount来获取数量)

  1. 点击返回按钮,调用顺序,在任何一处调用都可以拦截点击事件。

在dispatchKeyEvent()中返回true,可以拦截点击事件,但仍然会被调用两次,另外两个函数不会被调用;

在onKeyDown()中返回true,仍按以下顺序,但不会调用onBackPressed();

在onBackPressed()中返回true,仍按以下顺序,拦截点击事件。

dispatchKeyEvent() event.getKeyCode() = true
onKeyDown() keyCode = true, event.getRepeatCount() = 0
dispatchKeyEvent() event.getKeyCode() = true
onBackPressed()

8、MotionEvent

http://stackoverflow.com/questions/15467255/getdowntime-and-geteventtime

event.getDownTime() 返回的是一系列事件发生时,第一次事件的事件(比如ACTION_DOWN)

evnet.getEventTime() 返回的是当前事件发生的时间,也是一些列事件的最后一次事件的时间(比如ACITON_UP)

9、

重写dispatchKeyEventPreIme()可以在输入法之前拦截按键事件,尤其是back键

dispatchKeyEventPreIme()
10、各种scroll

scrollBy(int x, int y) x,y为两个方向上移动的距离,scroll之后会留下空白区域;

smoothScrollBy(int dis, int duration) dis为移动距离,duration为移动距离的时间(毫秒),但如果设置时间不当,会导致移动距离未完成就结束scroll;

smoothScrollByOffset(int offset) offset不是移动的距离,而是listview中的具体position

smoothScrollToPositionFromTop(int postion, int offset) position为list中的具体一项,offset为指定项的位置在window左上角时,移动的距离;

11、popupwindow setTouchInterceptor(new View.OnTouchListener()...)

可以拦截touch事件,popupwindow会拦截到ACTION_OUTSIDE事件。

12、

int containerViewId = getResources().getIdentifier("content", "android.R.id", getPackageName());
int containerViewId = getResources().getIdentifier("rootView", "id", getPackageName());
13、Drawable

layer-list 设置drawable的层次结构

level-list 设置drawable的状态,可以通过setDrawableLevel来改变状态以显示不同的效果

14、改变window的进出场动画

getWindow().setWindowAnimations(R.style.BMBWindowSlideInOutFromRight);

15、改变View的层次,可以在动画显示时将View添加到层次较高的layer,防止Transition动画的遮挡。

ViewGroup viewGroup = (ViewGroup)getWindow().getDecorView();
viewGroup.getOverlay().add(btnDice);
viewGroup.getOverlay().add(btnSend);

16、监听ACTION_DOWN, ACTION_UP事件并播放动画时,可以考虑使用handler来保证动画的播放,并防止UI线程被阻塞。尤其是在onTouchEvent()中,不适合做耗时过长的动作,否则会使得后面的Touch事件无法被捕捉到

17、onMeasure()方法

MeasureSpec.EXACTLY:match_parent , accurate

MeasureSpec.AT_MOST:wrap_content

计算完之后需要调用以下方法才能生效:

setMeasuredDimension(mWidth, mHeight);

18、解决scrollview和listview的冲突问题,可以重写onMeasure:

@Override  
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
{  

    /** 
     * 解决ScrollView与ListView的嵌套问题 
     */  
    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,  MeasureSpec.AT_MOST);  

    super.onMeasure(widthMeasureSpec, expandSpec);  
} 

19、配置发生变化时,保持大量数据时比较耗时,可以考虑使用fragment

在运行时配置发生变化时,在Fragment中保存有状态的对象,并提供相应的getter和setter方法,在activity中调用用于get和set。(Fragment可以没有UI,仅作为保存对象使用)
a) 继承Fragment,声明引用指向你的有状态的对象
b) 当Fragment创建时调用setRetainInstance(boolean)
c) 把Fragment实例添加到Activity中
d) 当Activity重新启动后,使用FragmentManager对Fragment进行恢复

不使用onSaveIntanceState()的原因:

如果重新启动你的Activity需要恢复大量的数据,重新建立网络连接,或者执行其他的密集型操作,这样因为配置发生变化而完全重新启动可能会是一个慢的用户体验。并且,使用系统提供的onSaveIntanceState()的回调中,使用Bundle来完全恢复你Activity的状态是可能是不现实的(Bundle不是设计用来携带大量数据的(例如bitmap),并且Bundle中的数据必须能够被序列化和反序列化),这样会消耗大量的内存和导致配置变化缓慢。在这样的情况下,当你的Activity因为配置发生改变而重启,你可以通过保持一个Fragment来缓解重新启动带来的负担。这个Fragment可以包含你想要保持的有状态的对象的引用。

20、fragment声明周期

与activity声明周期比较

场景演示 : 切换到该Fragment
11-29 14:26:35.095: D/AppListFragment(7649): onAttach
11-29 14:26:35.095: D/AppListFragment(7649): onCreate
11-29 14:26:35.095: D/AppListFragment(7649): onCreateView
11-29 14:26:35.100: D/AppListFragment(7649): onActivityCreated
11-29 14:26:35.120: D/AppListFragment(7649): onStart
11-29 14:26:35.120: D/AppListFragment(7649): onResume
屏幕灭掉:
11-29 14:27:35.185: D/AppListFragment(7649): onPause
11-29 14:27:35.205: D/AppListFragment(7649): onSaveInstanceState
11-29 14:27:35.205: D/AppListFragment(7649): onStop

屏幕解锁
11-29 14:33:13.240: D/AppListFragment(7649): onStart
11-29 14:33:13.275: D/AppListFragment(7649): onResume

切换到其他Fragment:
11-29 14:33:33.655: D/AppListFragment(7649): onPause
11-29 14:33:33.655: D/AppListFragment(7649): onStop
11-29 14:33:33.660: D/AppListFragment(7649): onDestroyView

切换回本身的Fragment:
11-29 14:33:55.820: D/AppListFragment(7649): onCreateView
11-29 14:33:55.825: D/AppListFragment(7649): onActivityCreated
11-29 14:33:55.825: D/AppListFragment(7649): onStart
11-29 14:33:55.825: D/AppListFragment(7649): onResume
回到桌面
11-29 14:34:26.590: D/AppListFragment(7649): onPause
11-29 14:34:26.880: D/AppListFragment(7649): onSaveInstanceState
11-29 14:34:26.880: D/AppListFragment(7649): onStop
回到应用
11-29 14:36:51.940: D/AppListFragment(7649): onStart
11-29 14:36:51.940: D/AppListFragment(7649): onResume

退出应用
11-29 14:37:03.020: D/AppListFragment(7649): onPause
11-29 14:37:03.155: D/AppListFragment(7649): onStop
11-29 14:37:03.155: D/AppListFragment(7649): onDestroyView
11-29 14:37:03.165: D/AppListFragment(7649): onDestroy
11-29 14:37:03.165: D/AppListFragment(7649): onDetach

21、配置发生变化,在menifest中进行属性设置,并在activity中自行对config的变化做适配(在onConfigChanged()方法中),就可以防止activity重建。

22、自定义Dialog,显示在底部

必须卸载onCreate里,利用window使其显示在屏幕下方,并且宽度占满屏幕。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.dialog_complex_condition_picker);
    ButterKnife.bind(this);
    Window window = getWindow();
    WindowManager.LayoutParams wlp = window.getAttributes();
    wlp.gravity = Gravity.BOTTOM;
    wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
    wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
    window.setAttributes(wlp);
    initViews();
}

自定义的style

<style name="ComplexConditionPickerDialog">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:windowFullscreen">false</item>
    <item name="android:windowIsTranslucent">false</item>
    <item name="android:windowFrame">@null</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowBackground">@color/transparent</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:backgroundDimEnabled">true</item>
    <item name="android:windowCloseOnTouchOutside">true</item>
    <!--<item name="android:windowAnimationStyle">@style/AnimRewardDialog</item>-->
</style>

23、解决Listview和ScrollView嵌套无法撑开的问题,可以重写onMeasure方法解决问题:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
            MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, expandSpec);
}

24、EditText获得焦点时自动弹出软键盘的解决方法

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
}
});

25、Window和Display测试

private void testDisplay(String from){
    BMBLogUtils.d(Config.LOGTAG, " ======= TestDisplay "+from+"=======");
    Window window = getWindow();
    Display display = window.getWindowManager().getDefaultDisplay();
    View decorView = window.getDecorView();
    BMBLogUtils.d(Config.LOGTAG, " TestDisplay window = "+(window == null ? "null":window)
            +", display = "+(display == null ? "null" : display)+", decorView = "+(decorView == null ? "null" : decorView));
    //1
    Point outPoint = new Point();
    display.getSize(outPoint);
    BMBLogUtils.d(Config.LOGTAG, "1. TestDisplay display.getSize(outPoint), outPoint = "+outPoint.toString());
    //2
    Point realSize = new Point();
    display.getRealSize(realSize);//API level 17
    BMBLogUtils.d(Config.LOGTAG, "2. TestDisplay display.getRealSize(realSize), realSize = " + realSize.toString());
    //3
    Point smallPoint = new Point();
    Point largePoint = new Point();
    display.getCurrentSizeRange(smallPoint, largePoint);
    BMBLogUtils.d(Config.LOGTAG, "3. TestDisplay display.getCurrentSizeRange(smallPoint, largePoint), smallPoint = "
            + smallPoint.toString() + ", largePoint = " + largePoint.toString());
    //4
    Rect rectSize = new Rect();
    display.getRectSize(rectSize);
    BMBLogUtils.d(Config.LOGTAG, "4. TestDisplay display.getRectSize(rectSize), rectSize = " + rectSize.toString());
    //5
    DisplayMetrics displayMatrix = new DisplayMetrics();
    display.getMetrics(displayMatrix);
    BMBLogUtils.d(Config.LOGTAG, "5. TestDisplay display.getMetrics(displayMatrix), displayMatrix = " + displayMatrix.toString());
    //6
    DisplayMetrics realDisplayMatrix = new DisplayMetrics();
    display.getRealMetrics(realDisplayMatrix);//API level 17
    BMBLogUtils.d(Config.LOGTAG, "6. TestDisplay display.getRealMetrics(realDisplayMatrix), realDisplayMatrix = " + realDisplayMatrix.toString());
    //7
    WindowManager.LayoutParams windowParams = window.getAttributes();
    BMBLogUtils.d(Config.LOGTAG, "7. TestDisplay windowParams = window.getAttributes(), windowParams = " + windowParams.toString());
    //8
    ViewGroup.LayoutParams decorViewParams = decorView.getLayoutParams();
    if(decorViewParams == null){
        BMBLogUtils.d(Config.LOGTAG, "8. TestDisplay decorViewParams = decorView.getLayoutParams(), decorViewParams = "+"null");
    }else{
        BMBLogUtils.d(Config.LOGTAG, "8. TestDisplay decorViewParams = decorView.getLayoutParams(), decorViewParams = VG.LayoutParams{height = " + decorViewParams.height + ", width = " + decorViewParams.width + "}");
    }
    //9
    Rect visibleFrameRect = new Rect();
    decorView.getWindowVisibleDisplayFrame(visibleFrameRect);
    BMBLogUtils.d(Config.LOGTAG, "9. TestDisplay visibleFrameRect = decorView.getWindowVisibleDisplayFrame(visibleFrameRect), visibleFrameRect = " + visibleFrameRect.toString());
    BMBLogUtils.d(Config.LOGTAG, " ======================= END ======================");
}

D/XIANZHEZLOGTAG(20345): ======= TestDisplay onCreate()=======
D/XIANZHEZLOGTAG(20345): TestDisplay window = com.android.internal.policy.impl.PhoneWindow@42b0e868, display = Display id 0: DisplayInfo{"内置屏幕", app 1080 x 1920, real 1080 x 1920, largest app 1794 x 1845, smallest app 1080 x 1005, 60.0 fps, rotation0, density 480 (442.451 x 443.345) dpi, layerStack 0, type BUILT_IN, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}, DisplayMetrics{density=3.0, width=1080, height=1920, scaledDensity=3.0, xdpi=442.451, ydpi=443.345}, isValid=true, decorView = com.android.internal.policy.impl.PhoneWindow$DecorView{42b495a0 V.E..... R.....ID 0,0-0,0}
D/XIANZHEZLOGTAG(20345): 1. TestDisplay display.getSize(outPoint), outPoint = Point(1080, 1920)
D/XIANZHEZLOGTAG(20345): 2. TestDisplay display.getRealSize(realSize), realSize = Point(1080, 1920)
D/XIANZHEZLOGTAG(20345): 3. TestDisplay display.getCurrentSizeRange(smallPoint, largePoint), smallPoint = Point(1080, 1005), largePoint = Point(1794, 1845)
D/XIANZHEZLOGTAG(20345): 4. TestDisplay display.getRectSize(rectSize), rectSize = Rect(0, 0 - 1080, 1920)
D/XIANZHEZLOGTAG(20345): 5. TestDisplay display.getMetrics(displayMatrix), displayMatrix = DisplayMetrics{density=3.0, width=1080, height=1920, scaledDensity=3.0, xdpi=442.451, ydpi=443.345}
D/XIANZHEZLOGTAG(20345): 6. TestDisplay display.getRealMetrics(realDisplayMatrix), realDisplayMatrix = DisplayMetrics{density=3.0, width=1080, height=1920, scaledDensity=3.0, xdpi=442.451, ydpi=443.345}
D/XIANZHEZLOGTAG(20345): 7. TestDisplay windowParams = window.getAttributes(), windowParams = WM.LayoutParams{(0,0)(fillxfill) ty=2 fl=#810100 pfl=0x8 wanim=0x10302a1 meizuFlags=0x1 imeOffset=-1 splitActionBarHeight=0Meizu WM.LayoutParams [ flags=0x0] }
D/XIANZHEZLOGTAG(20345): 8. TestDisplay decorViewParams = decorView.getLayoutParams(), decorViewParams = null
D/XIANZHEZLOGTAG(20345): 9. TestDisplay visibleFrameRect = decorView.getWindowVisibleDisplayFrame(visibleFrameRect), visibleFrameRect = Rect(0, 0 - 1080, 1920)
D/XIANZHEZLOGTAG(20345): ======================= END ======================
D/XIANZHEZLOGTAG(20345): ======= TestDisplay onWindowFocusChanged=======
D/XIANZHEZLOGTAG(20345): TestDisplay window = com.android.internal.policy.impl.PhoneWindow@42b0e868, display = Display id 0: DisplayInfo{"内置屏幕", app 1080 x 1920, real 1080 x 1920, largest app 1794 x 1845, smallest app 1080 x 1005, 60.0 fps, rotation0, density 480 (442.451 x 443.345) dpi, layerStack 0, type BUILT_IN, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}, DisplayMetrics{density=3.0, width=1080, height=1920, scaledDensity=3.0, xdpi=442.451, ydpi=443.345}, isValid=true, decorView = com.android.internal.policy.impl.PhoneWindow$DecorView{42b495a0 V.E..... R.....ID 0,0-1080,1776}
D/XIANZHEZLOGTAG(20345): 1. TestDisplay display.getSize(outPoint), outPoint = Point(1080, 1920)
D/XIANZHEZLOGTAG(20345): 2. TestDisplay display.getRealSize(realSize), realSize = Point(1080, 1920)
D/XIANZHEZLOGTAG(20345): 3. TestDisplay display.getCurrentSizeRange(smallPoint, largePoint), smallPoint = Point(1080, 1005), largePoint = Point(1794, 1845)
D/XIANZHEZLOGTAG(20345): 4. TestDisplay display.getRectSize(rectSize), rectSize = Rect(0, 0 - 1080, 1920)
D/XIANZHEZLOGTAG(20345): 5. TestDisplay display.getMetrics(displayMatrix), displayMatrix = DisplayMetrics{density=3.0, width=1080, height=1920, scaledDensity=3.0, xdpi=442.451, ydpi=443.345}
D/XIANZHEZLOGTAG(20345): 6. TestDisplay display.getRealMetrics(realDisplayMatrix), realDisplayMatrix = DisplayMetrics{density=3.0, width=1080, height=1920, scaledDensity=3.0, xdpi=442.451, ydpi=443.345}
D/XIANZHEZLOGTAG(20345): 7. TestDisplay windowParams = window.getAttributes(), windowParams = WM.LayoutParams{(0,0)(fillxfill) sim=#100 ty=1 fl=#1810100 pfl=0x8 wanim=0x10302a1 meizuFlags=0x1 imeOffset=-1 splitActionBarHeight=0Meizu WM.LayoutParams [ flags=0x0] }
D/XIANZHEZLOGTAG(20345): 8. TestDisplay decorViewParams = decorView.getLayoutParams(), decorViewParams = VG.LayoutParams{height = -1, width = -1}
D/XIANZHEZLOGTAG(20345): 9. TestDisplay visibleFrameRect = decorView.getWindowVisibleDisplayFrame(visibleFrameRect), visibleFrameRect = Rect(0, 75 - 1080, 1776)
D/XIANZHEZLOGTAG(20345): ======================= END ======================

26、hashCode()和equals()的关系

hashCode()的返回值和equals()的关系如下:
•如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。
•如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。
equals()先要查null和是否是同一类型。查同一类型是为了避免出现ClassCastException这样的异常给丢出来。查 null是为了避免出现NullPointerException这样的异常给丢出来。

27、layout animation

分为5种

LayoutTransition.APPEARING

LayoutTransition.DISAPPEARING

LayoutTransition.CHANGING

LayoutTransition.CHANGE_APPEARING

LayoutTransition.CHANGE_DISAPPEARING

有些种类会有默认的动画,一旦使能layout animation会默认出现,如果不想出现默认的效果,需要手动设为null,如:

lt.setAnimator(LayoutTransition.CHANGE_APPEARING, null);

28、measure()

在UI未渲染出来之前是无法直接getHeight(), getWidth()来获取高宽的,需要先measure(),然后getMeasuredHeight(), getMeasuredWidth()来获取高宽。在measure时的MeasureSpec很重要,应配合view的布局参数选择适当的Mode。

可用于测量wrap_content的:

View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);

29、activity start时显示键盘,只需要在Manifest里为该Activity添加以下属性

android:windowSoftInputMode="stateVisible"

30、获得activity content view:

findViewById(android.R.id.content)

31、当ImageView中加载图片与实际图片大小或者比例不一致时,应考虑使用以下属性来做适配:

android:adjustViewBounds="true"

32、隐藏status bar,完全不显示:

You can do it programatically:

public class ActivityName extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// remove title
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
}
}
Or you can do it via your AndroidManifest.xml file:

33、TouchEvent的分发

View:

1、dispatchTouchEvent
2、 setOnTouchListener的onTouch
3、onTouchEvent
ViewGroup:

1、ViewGroup的dispatchTouchEvent
2、ViewGroup的onInterceptTouchEvent
3、child View的dispatchTouchEvent
4、child View的onTouchEvent

34、