編輯:關於Android編程
要獲取屏幕寬高,我們可以先從android的界面構成了解
android的界面主要由三部分構成:1、狀態欄 2、標題欄 3、內容區域
\
狀態欄主要用來顯示一些系統圖標,應用的通知圖標和系統時間。
android中標題欄主要用來顯示當前位置,3.0過後添加了ActionBar,擁有了導航和OptionMenu的功能,5.0又新添加了ToolBar控件,和ActionBar類似,但自定義的空間更充足
android中的內容區域,實際上是一塊系統默認的名為android.id.content的單幀布局,setContentView()方法相當於添加View到這個單幀布局中,並覆蓋。
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DisplayMetrics dm = new DisplayMetrics(); // 獲取屏幕信息 getWindowManager().getDefaultDisplay().getMetrics(dm); int screenWidth = dm.widthPixels; int screenHeigh = dm.heightPixels; Log.v("獲取屏幕寬度", "寬度:" + screenWidth + ",高度:" + screenHeigh); }
控件View有getHeight()和getwidth()方法可以獲取寬高,但是如果直接在onCreate()方法中獲取控件寬高,獲取到的值是0,至於原因的是因為onCreate()方法中只是提供了數據初始化此時還沒有正式繪制圖形。而繪制圖形在OnDraw中進行,此時計算又顯得太晚。容易想到的辦法是:希望能在程序剛剛測量好某個指定控件後,拿到它的寬度和高度立刻進行計算或數據初始化。這就需要有一個方法來監聽到這個事件的發生,幸好Android提供了這樣的機制,利用View類中的getViewTreeObserver方法,可以獲取到指定View的觀察者,在繪制控件前的一剎那進行回調,這樣速度上又不耽誤,得到的數據由是准確的。
public class MainActivity extends AppCompatActivity { TextView firstTxt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); firstTxt = (TextView) findViewById(R.id.hello_word_txt); ViewTreeObserver viewTreeObserver = firstTxt.getViewTreeObserver(); viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { int height = firstTxt.getHeight(); int width = firstTxt.getWidth(); Log.v("獲取TextView寬高", "寬度:" + width + ",高度:" + height); return true; } }); } }
關於方法二,下面有一段我自己的簡單理解
將一個runnable添加到Layout隊列中:View.post()
簡單地說,只要用View.post()一個runnable就可以了。runnable對象中的方法會在View的measure、layout等事件後觸發UI事件隊列會按順序處理事件。在setContentView()被調用後,事件隊列中會包含一個要求重新layout的message,所以任何你post到隊列中的東西都會在Layout發生變化後執行。
firstTxt.post(new Runnable() { @Override public void run() { firstTxt.getHeight(); //height is ready firstTxt.getWidth(); } }
上面提到過繪制控件是在ondraw()方法中進行,在ondraw中獲取控件寬高則太晚,而在onMeasure()中測量又太早。那我們嘗試在onLayout()中獲取控件寬高是否可行。 onLayout()和ondraw()都是控件View生命周期中的回調方法。至於View的生命周期,我也還沒接觸過,等後面深入學習了再總結一下。
首先新建一個類繼承自TextView,然後重寫裡面的onLayout()和onMeasure()方法
public class MyTextView extends TextView { public MyTextView(Context context) { super(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public MyTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); } //===========上面為繼承TextView默認的實現方法,我們可以不管 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //獲取MyTextView當前實例的高 int height = this.getHeight(); //獲取MyTextView當前實例的寬 int width = this.getWidth(); //通過Log.v打印輸出顯示 Log.v("onMeasure獲取控件寬高", "高:" + height + ",寬:" + width); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //獲取MyTextView當前實例的高 int height = this.getHeight(); //獲取MyTextView當前實例的寬 int width = this.getWidth(); //通過Log.v打印輸出顯示 Log.v("onLayout獲取控件寬高", "高:" + height + ",寬:" + width); } }
再在程序入口的Acitvity中的onCreate()方法中實例化自定義的MyTextView
public class MainActivity extends AppCompatActivity { MyTextView mMyTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMyTextView = (MyTextView) findViewById(R.id.mytextview_txt); } }
從上面可以看出MyTextView第一次回調onMeasure()方法時,還沒有獲取到控件的寬高數據。上面提到過"如果直接在onCreate()方法中獲取控件寬高,獲取到的值是0",那我們可以假設一下activity的onCreate()方法執行時在View執行第一次onMeasure()方法之前,我們嘗試通過以下方法看能否驗證這一假設
首先在上面新建的MyTextView中添加兩個我們自定義的方法,一個是setMyTextViewSize(),另外一個是getMyTextViewSize(),代碼如下:
public class MyTextView extends TextView { int mMyTextViewHeight; int mMyTextViewWidth; public MyTextView(Context context) { super(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public MyTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); } //===========上面為繼承TextView默認的實現方法,我們可以不管 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //獲取MyTextView當前實例的高 int height = this.getHeight(); //獲取MyTextView當前實例的寬 int width = this.getWidth(); //調用setMyTextViewSize,使其他類可以通過getMyTextViewSize()可以獲取到 //mMyTextViewHeight和mMyTextViewWidth變量的值,即高和寬 setMyTextViewSize(height, width); //通過Log.v打印輸出顯示 Log.v("onMeasure獲取控件寬高", "高:" + height + ",寬:" + width); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //獲取MyTextView當前實例的高 int height = this.getHeight(); //獲取MyTextView當前實例的寬 int width = this.getWidth(); //與上同理 setMyTextViewSize(height, width); //通過Log.v打印輸出顯示 Log.v("onLayout獲取控件寬高", "高:" + height + ",寬:" + width); } public void setMyTextViewSize(int height, int width) { mMyTextViewHeight = height; mMyTextViewWidth = width; } public int[] getMyTextViewSize() { int[] viewSize = new int[]{mMyTextViewHeight, mMyTextViewWidth}; return viewSize; } }
再在程序入口的Acitvity的onCreate()方法中上面已經實例化得到的MyTextView的getMyTextViewsize()方法嘗試獲取控件寬高
public class MainActivity extends AppCompatActivity { MyTextView mMyTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMyTextView = (MyTextView) findViewById(R.id.mytextview_txt); int[] myTextViewSize = mMyTextView.getMyTextViewSize(); Log.v("入口acitivity的onCreate獲取控件寬高", "高:" + myTextViewSize[0] + ",寬:" + myTextViewSize[1]); } }運行打印輸出顯示:
通過上圖可以發現Acitivity的onCreate()方法執行時機是在View的第一次回調onMeasure()之前,View第一次回調onMeasure()方法的時候還沒有獲取到寬高,自然Acitivity的onCreate()方法中也無法獲取到控件寬高。那麼,通過上面的打印信息,我們可以設想如果在onLayout()方法已經獲取到View的寬高時,Activity的onCreate()再獲取寬高就行了。我想到的一種思路是在Acitivity的onCreate()方法循環調用MyTextView的onLayout()方法,但是我們直到在android的主線程也就是UI線程中執行死循環會導致頁面無法顯示,那麼我們應該在onCreate()方法中開辟一條子線程 ,方法循環調用MyTextView的onLayout()方法,直到獲取到寬高。要實現這個思路的話,我們可以用到Handler。
下面是具體的代碼實現:
public class MainActivity extends AppCompatActivity { MyTextView mMyTextView; //使用Handler默認的無參構造方法時,Handler執行的線程即聲明Handler的線程,在這裡是在主線程,也就是UI線程中 Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { Log.v("Handler獲取控件寬高", "高:" + msg.arg1 + ",寬:" + msg.arg2); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMyTextView = (MyTextView) findViewById(R.id.mytextview_txt); new Thread(new Runnable() { @Override public void run() { int[] viewSize = mMyTextView.getMyTextViewSize(); Log.v("onCreate()獲取控件寬高", "高:" + viewSize[0] + ",寬:" + viewSize[1]); while (viewSize[0] == 0) { viewSize = mMyTextView.getMyTextViewSize(); if (viewSize[0] != 0) { Message msg = Message.obtain(); msg.arg1 = viewSize[0]; msg.arg2 = viewSize[1]; mHandler.sendMessage(msg); } } } }).start(); } }
通過上面的方法我們就可以在onCreate()方法中獲取View的寬高了
1.RxJava概述ReactiveX與RxJava在講到RxJava之前我們首先要了解什麼是ReactiveX,因為RxJava是ReactiveX的一種java實現。
一、Android內存基礎物理內存與進程內存物理內存即移動設備上的RAM,當啟動一個Android程序時,會啟動一個Dalvik VM進程,系統會給它分配固定的內存空間(
Android提供了大量的標准Action,Category:例子,查看並獲取聯系人電話用戶點擊按鈕值會顯示系統的聯系人列表,當用戶單擊聯系人之後,程序將會顯示該聯系人的
1. View 樹的繪圖流程當 Activity 接收到焦點的時候,它會被請求繪制布局,該請求由Android framework 處理.繪制是從根節點開始,