Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發-基本概念小整理------為了面試

Android開發-基本概念小整理------為了面試

編輯:關於Android編程

1.請解釋下在單線程模型中Message,Handler,Message Queue,Looper之間的關系。

簡單的說,Handler獲取當前線程中的looper對象,looper用來從存放Message的MessageQueue中取出Message,再有Handler進行Message的分發和處理。

Message Queue(消息隊列):用來存放通過Handler發布的消息,通常附屬於某一個創建它的線程,可以通過Looper.myQueue()得到當前線程的消息隊列。

Handler:可以發布或者處理一個消息或者操作一個Runnable,通過Handler發布消息,消息將只會發送到與它關聯的消息隊列,也只能處理該消息隊列中的消息。

Looper:是Handler和消息隊列之間通訊橋梁,程序組件首先通過Handler把消息傳遞給Looper,Looper把消息放入隊列。Looper也把消息隊列裡的消息廣播給所有的。

Handler:Handler接受到消息後調用handleMessage進行處理。

Message:消息的類型,在Handler類中的handleMessage方法中得到單個的消息進行處理。

在單線程模型下,為了線程通信問題,Android設計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue並結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:

1. Message

Message消息,理解為線程間交流的信息,處理數據後台線程需要更新UI,則發送Message內含一些數據給UI線程。

2. Handler

Handler處理者,是Message的主要處理者,負責Message的發送,Message內容的執行處理。後台線程就是通過傳進來的 Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message)方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。

3. Message Queue

Message Queue消息隊列,用來存放通過Handler發布的消息,按照先進先出執行。

每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾並按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被 Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。

4. Looper

Looper是每條線程裡的Message Queue的管家。Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程裡並沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調用Looper.myLooper() 得到當前線程的Looper就有可能為NULL。對於子線程使用Looper,API Doc提供了正確的使用方法:這個Message機制的大概流程:

1. 在Looper.loop()方法運行開始後,循環地按照接收順序取出Message Queue裡面的非NULL的Message。

2. 一開始Message Queue裡面的Message都是NULL的。當Handler.sendMessage(Message)到Message Queue,該函數裡面設置了那個Message對象的target屬性是當前的Handler對象。隨後Looper取出了那個Message,則調用 該Message的target指向的Hander的dispatchMessage函數對Message進行處理。在dispatchMessage方法裡,如何處理Message則由用戶指定,三個判斷,優先級從高到低:

1) Message裡面的Callback,一個實現了Runnable接口的對象,其中run函數做處理工作;

2) Handler裡面的mCallback指向的一個實現了Callback接口的對象,由其handleMessage進行處理;

3) 處理消息Handler對象對應的類繼承並實現了其中handleMessage函數,通過這個實現的handleMessage函數處理消息。

由此可見,我們實現的handleMessage方法是優先級最低的!

3. Handler處理完該Message (update UI) 後,Looper則設置該Message為NULL,以便回收!

在網上有很多文章講述主線程和其他子線程如何交互,傳送信息,最終誰來執行處理信息之類的,個人理解是最簡單的方法——判斷Handler對象裡面的Looper對象是屬於哪條線程的,則由該線程來執行!

1. 當Handler對象的構造函數的參數為空,則為當前所在線程的Looper;

2. Looper.getMainLooper()得到的是主線程的Looper對象,Looper.myLooper()得到的是當前線程的Looper對象。

2.如果有個100M大的文件,需要上傳至服務器中,而服務器form表單最大只能上傳2M,可以用什麼方法。

使用Http協議上傳數據,特別是在Android下,跟form沒什麼關系。傳統的在web中,在form中寫文件上傳,其實浏覽器所做的就是將我們的數據進行解析組拼成字符串,以流的方式發送到服務器,且上傳文件用的都是POST方式,POST方式對大小沒什麼限制。

3、內存溢出和內存洩漏有什麼區別?何時會產生內存洩漏?內存優化有哪些方法?

內存溢出通俗理解就是軟件(應用)運行需要的內存,超出了它可用的最大內存。

內存洩漏就是我們對某一內存空間的使用,使用完成後沒有釋放。

內存優化:Android中容易內存溢出的部分,就是圖片的加載,我們可以使用圖片的壓縮加上使用LruCache緩存的目的

來控制圖片所能夠使用的內存。還有對於比較耗資源的對象及時的關閉,例如Database Conn,各種傳感器,Service等等。

4.AsyncTask使用在哪些場景?它的缺陷是什麼?如何解決?

AsyncTask 運用的場景就是我們需要進行一些耗時的操作,耗時操作完成後更新主線程,或者在操作過程中對主線程的UI進行更新。

缺陷:AsyncTask中維護著一個長度為128的線程池,同時可以執行5個工作線程,還有一個緩沖隊列,當線程池中已有128個線程,緩沖隊列已滿時,如果此時向線程提交任務,將會拋出RejectedExecutionException。

解決的方法:由一個控制線程來處理AsyncTask的調用判斷線程池是否滿了,如果滿了則線程睡眠否則請求AsyncTask繼續處理。

5.assest文件夾裡放文件,對於文件的大小有沒有限制?

assets目錄更像一個附錄類型的目錄,Android不會為這個目錄中的文件生成ID並保存在R類當中,因此它與Android中的一些類和方法兼容度更低。同時,由於你需要一個字符串路徑來獲取這個目錄下的文件描述符,訪問的速度會更慢。但是把一些文件放在這個目錄下會使一些操作更加方便,比方說拷貝一個數據庫文件到系統內存中。要注意的是,你無法在Android XML文件中引用到assets目錄下的文件,只能通過AssetManager來訪問這些文件。數據庫文件和游戲數據等放在這個目錄下是比較合適的。這兩者中單個文件大小不能超過1M的錯誤描述也在傳播,即如果讀取超過1M的文件會報IOException,還引申出種種解決方案。不應該有這樣的限制,為了驗證這個說法寫了個Demo,發現將近5M的壓縮包在assets和raw中都能正常訪問,在這裡糾正一下,理論上只要打包不超過Android APK 50M大小的限制都是沒有問題的。當然了,不排除是Android很早期的時候因為設備硬件原因aapt在編譯的時候對這兩個文件夾大小做出了限制,如果是這樣,較新版的ADT應該不會出現這種情況。

6.啟動一個程序,可以主界面點擊圖標進入,也可以從一個程序中跳轉過去,二者有什麼區別?

是因為啟動程序(主界面也是一個app),發現了在這個程序中存在一個設置為的activity,所以這個launcher會把icon提出來,放在主界面上。當用戶點擊icon的時候,發出一個Intent:Intent intent = mActivity.getPackageManager().getLaunchIntentForPackage(packageName);

mActivity.startActivity(intent);跳過去可以跳到任意允許的頁面,如一個程序可以下載,那麼真正下載的頁面可能不是首頁(也有可能是首頁),這時還是構造一個Intent,startActivity。

這個intent中的action可能有多種view,download都有可能。系統會根據第三方程序向系統注冊的功能,為你的Intent選擇可以打開的程序或者頁面。所以唯一的一點不同的是從icon的點擊啟動的intent的action是相對單一的,從程序中跳轉或者啟動可能樣式更多一些。本質是相同的。

7.程序之間的親和性的理解。

1、默認情況下一個應用的所有Activity都是具有相同的affinity,都是從application中繼承,application的affinity

默認就是manifest的包名。

2、affinity對Activity來說,就像是身份證一樣,可以告訴所在的Task,自己屬於其中的一員。

3、應用場合:

a:根據affinity重新為Activity選擇合適的宿主Task;

b:與allowTaskReparenting屬性配合;

c:啟動Activity使用Intent設置了FLAG_ACTIVITY_NEW_TASK標記。

8.同一個程序,但不同的Activity是否可以放在不同的Task任務棧中?

可以放在不同的Task中。需要為不同的activity設置不同的affinity屬性,啟動activity的Intent需要包含FLAG_ACTIVITY_NEW_TASK標記。

9.橫豎屏切換時候Activity的生命周期。

1、不設置Activity的android:configChanges時,切屏會重新調用各個生命周期,切橫屏時會執行一次,切豎屏時會執行兩次。

2、設置Activity的android:configChanges="orientation"時,切屏還是會重新調用各個生命周期,切橫、豎屏時只會執行一次。

3、設置Activity的android:configChanges="orientation|keyboardHidden"時,切屏不會重新調用各個生命周期,只會執行onConfigurationChanged方法。

10.AIDL的全稱是什麼?如何工作?

全稱是:Android Interface Define Language(Android接口定義語言)

在Android中, 每個應用程序都可以有自己的進程. 在寫UI應用的時候, 經常要用到Service. 在不同的進程中, 怎樣傳遞對象呢? 顯然, Java中不允許跨進程內存共享。

因此傳遞對象, 只能把對象拆分成操作系統能理解的簡單形式, 以達到跨界對象訪問的目的. 在J2EE中,采用RMI的方式, 可以通過序列化傳遞對象. 在Android中, 則采用AIDL的方式. 理論上AIDL可以傳遞Bundle,實際上做起來卻比較麻煩。

AIDL(AndRoid接口描述語言)是一種借口描述語言; 編譯器可以通過aidl文件生成一段代碼,通過預先定義的接口達到兩個進程內部通信進程的目的. 如果需要在一個Activity中, 訪問另一個Service中的某個對象, 需要先將對象轉化成AIDL可識別的參數(可能是多個參數), 然後使用AIDL來傳遞這些參數, 在消息的接收端, 使用這些參數組裝成自己需要的對象.AIDL的IPC的機制和COM或CORBA類似, 是基於接口的,但它是輕量級的。它使用代理類在客戶端和實現層間傳遞值. 如果要使用AIDL,需要完成2件事情: 1. 引入AIDL的相關類.; 2. 調用aidl產生的class。

AIDL的創建方法:

AIDL語法很簡單,可以用來聲明一個帶一個或多個方法的接口,也可以傳遞參數和返回值。 由於遠程調用的需要, 這些參數和返回值並不是任何類型。

下面是些AIDL支持的數據類型:

1. 不需要import聲明的簡單Java編程語言類型(int,boolean等)

2. String, CharSequence不需要特殊聲明

3. List, Map和Parcelables類型, 這些類型內所包含的數據成員也只能是簡單數據類型, String等其他比支持的類型

11.dvm的進程和Linux的進程, 應用程序的進程是否為同一個概念?

DVM指dalivk的虛擬機。每一個Android應用程序都在它自己的進程中運行,都擁有一個獨立的Dalvik虛擬機實例。而每一個DVM都是在Linux 中的一個進程,所以說可以認為是同一個概念。Dalvik是Google公司自己設計用於Android平台的Java虛擬機,每一個Dalvik 應用作為一個獨立的Linux 進程執行。獨立的進程可以防止在虛擬機崩潰的時候所有程序都被關閉。

12. 什麼是Activity?

四大組件之一,一般的,一個用戶交互界面對應一個activity, activity 是Context的子類,同時實現了window.callback和keyevent.callback, 可以處理與窗體用戶交互的事件. 我開發常用的的有ListActivity,PreferenceActivity 等…如果界面有共同的特點或者功能的時候,還會自己定義一個BaseActivity.

13. 請描述一下Activity生命周期。

onCreate: 在這裡創建界面 ,做一些數據 的初始化工作

onStart: 到這一步變成用戶可見不可交互的

onResume: 變成和用戶可交互的,(在activity 棧系統通過棧的方式管理這些個Activity的最上面,運行完彈出棧,

則回到上一個Activity)

onPause: 到這一步是可見但不可交互 的,系統會停止動畫 等消耗CPU 的事情從上文的描述已經知道,應該在這裡保存你的一些數據,因為這個時候你的程序的優先級降低,有可能被系統收回。在這裡保存的數據,應該在onResume裡讀出來,注意:這個方法裡做的事情時間要短,因為下一個activity不會等到這個方法完成才啟動

onstop: 變得不可見 ,被下一個activity覆蓋了

onDestroy: 這是activity被干掉前最後一個被調用方法了,可能是外面類調用finish方法或者是系統為了節省空間將它暫時性的干掉,可以用isFinishing()來判斷它,如果你有一個Progress Dialog在線程中轉動,請在onDestroy裡把他cancel掉,不然等線程結束的時候,調用Dialog的cancel方法會拋 異常的。

onPause,onstop, onDestroy,三種狀態下,activity都有可能被系統干掉為了保證程序的正確性,你要在onPause()裡寫上持久層操作的代碼,將用戶編輯的內容都保存到存儲介質上(一般都是數據庫 )。實際工作中因為生命周期的變化而帶來的問題也很多,比如你的應用程序起了新的線程在跑,這時候中斷了,你還要去維護那個線程,是暫停還是殺掉還是數據回滾,是吧?因為Activity可能被殺掉,所以線程中使用的變量和一些界面元素就千萬要注意了,一般我都是采用Android的消息機制

[Handler,Message]來處理多線程和界面交互的問題。

其實這些方法都是兩兩對應的,onCreate創建與onDestroy銷毀;onStart可見與onStop不可見;onResume可編輯(即焦點)與onPause;這6個方法是相對應的,那麼就只剩下一個onRestart方法了,這個方法在Activity被onStop後,但是沒有被onDestroy,在再次啟動此Activity時就調用onRestart(而不再調用onCreate)方法;如果被onDestroy了,則是調用onCreate方法。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved