Android面試記錄

自定義控件

原生控件:
文本控件:TextView和EditView
按鈕控件:Button和ImageButton
狀態開關按鈕:ToogleButton
單選按鈕或複選按鈕:CheckBox
圖片控件:ImageView
時鐘控件:AnalogClock 和 DigitalClock
進度條 ProgressBar 和日期與時間選擇控件 DatePicker 和 TimePicker 等

自定義控件:
自定義控件可以分爲兩種自定義組合控件和自定義 view。
一:自定義組合控件
解釋:自定義組合控件就是把多個控件做爲一個整體看待、處理。這樣的好處不僅可以減輕 xml 的代碼量,也提高了代碼的複用性。
1. 聲明一個 View 對象,繼承相對佈局,或者線性佈局或者其他的 ViewGroup。
2. 在自定義的 View 對象裏面重寫它的構造方法,在構造方法裏面就把佈局都初始化完畢。
3. 根據業務需求添加一些 api 方法,擴展自定義的組合控件;
4. 希望在佈局文件裏面可以自定義一些屬性。
5. 聲明自定義屬性的命名空間。
xmlns:itheima=”http://schemas.android.com/apk/res/com.itheima.mobilesafe”
6. 在 res 目錄下的 values 目錄下創建 attrs.xml 的文件聲明我們寫的屬性。
7. 在佈局文件中寫自定義的屬性。
8. 使用這些定義的屬性。自定義 View 對象的構造方法裏面有一個帶兩個參數的構造方法佈局文件裏面定義的屬性都放在 AttributeSet attrs,獲取那些定義的屬性。

二:自定義 view
自定義 View 首先要實現一個繼承自 View 的類。添加類的構造方法,通常是三個構造方法,不過從 Android5.0開始構造方法已經添加到 4 個了。override 父類的方法,如 onDraw,(onMeasure)等。如果自定義的 View 有自己的屬性,需要在 values 下建立 attrs.xml 文件,在其中定義屬性,同時代碼也要做修改。

Android佈局:

RelativeLayout(相對佈局):相對其它組件的佈局方式。這個最常用哦。
LinearLayout(線性佈局):按照垂直或者水平方向佈局的組件。
AbsoluteLayout(絕對佈局):按照絕對座標來佈局組件。現在用的比較少
TabLayout(表單佈局):按照行列方式佈局組件。
FrameLayout(幀佈局):組件從屏幕左上方佈局組件。
GrideLayout(android4.0推出)

事件分發

主要
dispatchTouchEvent
onTouchEvent
ACTION_DOWN
ACTION_MOVE
ACTION_UP

1、整個View的事件轉發流程是:
View.dispatchEvent->View.setOnTouchListener->View.onTouchEvent
在dispatchTouchEvent中會進行OnTouchListener的判斷,如果OnTouchListener不爲null且返回true,則表示事件被消費,onTouchEvent不會被執行;否則執行onTouchEvent
2、onTouchEvent中的DOWN,MOVE,UP
DOWN時:
a、首先設置標誌爲PREPRESSED,設置mHasPerformedLongPress=false ;然後發出一個115ms後的mPendingCheckForTap;
b、如果115ms內沒有觸發UP,則將標誌置爲PRESSED,清除PREPRESSED標誌,同時發出一個延時爲500-115ms的,檢測長按任務消息;
c、如果500ms內(從DOWN觸發開始算),則會觸發LongClickListener:
此時如果LongClickListener不爲null,則會執行回調,同時如果LongClickListener.onClick返回true,才把mHasPerformedLongPress設置爲true;否則mHasPerformedLongPress依然爲false;
MOVE時:
主要就是檢測用戶是否劃出控件,如果劃出了:
115ms內,直接移除mPendingCheckForTap;
115ms後,則將標誌中的PRESSED去除,同時移除長按的檢查:removeLongPressCallback();
UP時:
a、如果115ms內,觸發UP,此時標誌爲PREPRESSED,則執行UnsetPressedState,setPressed(false);會把setPress轉發下去,可以在View中複寫dispatchSetPressed方法接收;
b、如果是115ms-500ms間,即長按還未發生,則首先移除長按檢測,執行onClick回調;
c、如果是500ms以後,那麼有兩種情況:
i.設置了onLongClickListener,且onLongClickListener.onClick返回true,則點擊事件OnClick事件無法觸發;
ii.沒有設置onLongClickListener或者onLongClickListener.onClick返回false,則點擊事件OnClick事件依然可以觸發;
d、最後執行mUnsetPressedState.run(),將setPressed傳遞下去,然後將PRESSED標識去除;

setOnLongClickListener和setOnClickListener是否只能執行一個
不是的,只要setOnLongClickListener中的onClick返回false,則兩個都會執行;返回true則會屏幕setOnClickListener

APP的啓動流程

Activity啓動過程詳解
從桌面點擊到activity啓動的過程
1、Launcher線程捕獲onclick的點擊事件,調用Launcher.startActivitySafely,進一步調用Launcher.startActivity,最後調用父類Activity的startActivity。
2、Activity和ActivityManagerService交互,引入Instrumentation,將啓動請求交給Instrumentation,調用Instrumentation.execStartActivity。
3、調用ActivityManagerService的startActivity方法,這裏做了進程切換(具體過程請查看源碼)。
4、開啓Activity,調用onCreate方法

Handler機制

消息機制首先要了解 Handler,Looper,Message,MessageQueue
Handler:主要用來處理消息和更新UI,如果想Handler正常工作,在當前線程中要有一個Lopoer對象
Looper:Handler接受和處理消息的對象
Message:消息隊列先進先出的管理Message,在初始化Looper時會創建一個與之關聯的MessageQueue
MessageQuene:每個線程只能有一個Looper管理MessageQueun,不斷從中取出Message分發給對應的Handler

簡單點說:
當我們的子線程想修改Activity中的UI組件時,我們可以新建一個Handler對象,通過這個對象向主線程發送信息;而我們發送的信息會先到主線程的MessageQueue進行等待,由Looper按先入先出順序取出,再根據message對象的what屬性分發給對應的Handler進行處理!

Handler的相關方法:
sendEmptyMessage(int what):發送空消息
sendEmptyMessageDelayed(int what,long delayMillis):指定延時多少毫秒後發送空信息sendMessage(Message msg):立即發送信息
sendMessageDelayed(Message msg):指定延時多少毫秒後發送信息
final boolean hasMessage(int what):檢查消息隊列中是否包含what屬性爲指定值的消息 如果是參數爲(int what,Object object):除了判斷what屬性,還需要判斷Object屬性是否爲指定對象的消息

Handler的使用實例(寫在子線程,寫在主線程)
1 )直接調用Looper.prepare()方法即可爲當前線程創建Looper對象,而它的構造器會創建配套的MessageQueue;
2 )創建Handler對象,重寫handleMessage( )方法就可以處理來自於其他線程的信息了!
3 )調用Looper.loop()方法啓動Looper

一個應用中有哪些線程?

首先,我們都知道的UI線程即用戶交互線程,用來處理用戶消息和界面繪製;
其次,每個Binder對象對應一個線程;在ActivityThread中會創建ApplicationThread,他們都是繼承Binder,這裏會啓動兩個線程;
所以最少應該是3個線程…..然後開發人員自定義的子線程…..。

View的繪製

View的繪製主要涉及三個方法:onMeasure()、onLayout()、onDraw()
onMeasure主要用於計算view的大小,onLayout主要用於確定view在ContentView中的位置,onDraw主要是繪製View。
在執行onMeasure()、onLayout()方法時都會通過相應的標誌位或者對應的座標點來判斷是否需要執行對應的函數,如我們經常調用的invalidate方法就只會執行onDraw方法,因爲此時的視圖大小和位置均未發生變化,除非調用requestLayout方法完整強制進行view的繪製,從而執行上面三個方法。
進度條組件:ProgressView AnnotationView

都使用過哪些自定義控件

1.pull2RefreshListView
2.LazyViewPager
3.SlidingMenu
4.SmoothProgressBar
5.自定義組合控件
6.ToggleButton
7.自定義吐司(Toast)

圖片加載框架的優劣對比(Picasso, ImageLoader, Fresco, Glide)

安卓幾種圖片加載框架的比較:http://blog.csdn.net/u013134722/article/details/56676078

開發中都使用過哪些框架,平臺

框架
EventBus(事件處理)
事件總線機制:
xUtils(網絡、圖片、ORM)

Gson(解析 json 數據框架)
使用方法:

imageLoader (圖片處理框架)
源碼:

zxing (二維碼掃描)
怎麼使用

平臺
JPush(推送平臺)
友盟(統計平臺)
有米(優米)(廣告平臺)
百度地圖
bmob(服務器平臺、短信驗證、郵箱驗證、第三方支付、消息推送、即時通訊)
阿里雲 OSS(雲存儲)
ShareSDK(分享平臺、第三方登錄)

應用上線後用戶使用過程中出現的BUG你們是怎麼收集的?

Android 中如何捕獲未捕獲的異常
一:UncaughtExceptionHandler
1、自 定 義 一 個 Application , 比 如 叫 MyApplication 繼 承 Application 實 現
UncaughtExceptionHandler。
2、覆寫 UncaughtExceptionHandler 的 onCreate 和 uncaughtException 方法。

@Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(final Thread thread, final Throwable ex) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
System.out.println(Thread.currentThread());
Toast.makeText(getApplicationContext(), "thread="+thread.getId()+"
ex="+ex.toString(), 1).show();
Looper.loop();
}
}).start();
SystemClock.sleep(3000);
android.os.Process.killProcess(android.os.Process.myPid());
}
}

注意:上面的代碼只是簡單的將異常打印出來。
在 onCreate 方法中我們給 Thread 類設置默認異常處理 handler,如果這句代碼不執行則一切
都是白搭。
在 uncaughtException 方法中我們必須新開闢個線程進行我們異常的收集工作,然後將系統給
殺死。
3、在 AndroidManifest 中配置該 Application

<application
android:name="com.example.uncatchexception.MyApplication"

二:Bug 收集工具 Crashlytics
Crashlytics 是專門爲移動應用開發者提供的保存和分析應用崩潰的工具。國內主要使用的是友
盟做數據統計。
Crashlytics 的好處:
1.Crashlytics 不會漏掉任何應用崩潰信息。
2.Crashlytics 可以象 Bug 管理工具那樣,管理這些崩潰日誌。
3.Crashlytics 可以每天和每週將崩潰信息彙總發到你的郵箱,所有信息一目瞭然。
使用步驟:
1.註冊需要審覈通過才能使用,國內同類產品頂多發個郵箱激活鏈接;
2.支持 Eclipse、Intellij IDEA 和 Android Studio 等三大 IDE;
3.Eclipse 插件是 iOS 主題風格 UI,跟其他 plugin 在一起簡直是鶴立雞羣;
4.只要登錄帳號並選擇項目,會自動導入 jar 包並生成一個序列號,然後在 AndroidManifest.xml
和啓動 Activity 的入口添加初始化代碼,可以說是一鍵式操作,當然要使用除錯誤統計外的其他功能
還是得自己添加代碼;
5.不像友盟等國內同類產品,將固定的序列號直接寫入 xml 文件,而是動態自動生成的;當然這個存
放序列號的 xml 文件也是不能修改和提交到版本控制系統的;
6.後臺可以設置郵件提醒,當然這個最好不要開啓,Android 開發那數量驚人、千奇百怪的錯誤信息
你懂的。
7.不僅能統計到 UncaughtException 這種未捕獲的 Crash 異常信息,只要在 try/catch 代碼塊的
catch 中添加一行代碼就能統計到任何異常;
try{ myMethodThatThrows(); }catch(Exception
e){ Crashlytics.logException(e); //handle your exception here! }
8.相當詳細的錯誤信息,不僅僅是簡單的打印 StackTrace 信息;並且能看到最近一次 crash 的機器
可用內存等信息,而不僅僅是簡單統計機型和版本號。
使用連接:http://blog.csdn.net/smking/article/details/39320695

屏幕適配問題

適配方式之 dp
適配方式之 dimens
適配方式之 layout
適配方式之 java 代碼適配
適配方式之 weight 權重適配

屏幕適配有哪些處理技巧

跨進程通信AIDL

1、什麼是 AIDL 以及如何使用
①aidl 是 Android interface definition Language 的英文縮寫,意思 Android 接口定義語言。
②使用 aidl 可以幫助我們發佈以及調用遠程服務,實現跨進程通信。
③將服務的 aidl 放到對應的 src 目錄,工程的 gen 目錄會生成相應的接口類
我們通過 bindService(Intent,ServiceConnect,int)方法綁定遠程服務,在 bindService
中 有 一 個 ServiceConnec 接 口 , 我 們 需 要 覆 寫 該 類 的
onServiceConnected(ComponentName,IBinder)方法,這個方法的第二個參數 IBinder 對象其實
就是已經在 aidl 中定義的接口,因此我們可以將 IBinder 對象強制轉換爲 aidl 中的接口類。
我們通過 IBinder 獲取到的對象(也就是 aidl 文件生成的接口)其實是系統產生的代理對象,該
代理對象既可以跟我們的進程通信, 又可以跟遠程進程通信, 作爲一箇中間的角色實現了進程間通信。

2、AIDL 的全稱是什麼?如何工作?能處理哪些類型的數據?
AIDL 全稱 Android Interface Definition Language(AndRoid 接口描述語言) 是一種接口描述
語言; 編譯器可以通過 aidl 文件生成一段代碼,通過預先定義的接口達到兩個進程內部通信進程跨界
對象訪問的目的。需要完成 2 件事情: 1. 引入 AIDL 的相關類.; 2. 調用 aidl 產生的 class.理論上, 參
數可以傳遞基本數據類型和 String, 還有就是 Bundle 的派生類, 不過在 Eclipse 中,目前的 ADT 不支
持 Bundle 做爲參數。

說一說一個你熟悉的圖片框架

一:imageload
多線程下載圖片,圖片可以來源於網絡,文件系統,項目文件夾assets中以及drawable中等
支持隨意的配置ImageLoader,例如線程池,圖片下載器,內存緩存策略,硬盤緩存策略,圖片顯示選項以及其他的一些配置
支持圖片的內存緩存,文件系統緩存或者SD卡緩存
支持圖片下載過程的監聽
根據控件(ImageView)的大小對Bitmap進行裁剪,減少Bitmap佔用過多的內存
較好的控制圖片的加載過程,例如暫停圖片加載,重新開始加載圖片,一般使用在ListView,GridView中,滑動過程中暫停加載圖片,停止滑動的時候去加載圖片
提供在較慢的網絡下對圖片進行加載

說一說一個你熟悉的網絡框架

說一說數據結構和算法

講一講你們做項目的流程

View的繪製

首先,我們都知道的UI線程即用戶交互線程,用來處理用戶消息和界面繪製;
其次,每個Binder對象對應一個線程;在ActivityThread中會創建ApplicationThread,他們都是繼承Binder,這裏會啓動兩個線程;
所以最少應該是3個線程…..然後開發人員自定義的子線程…..。

Android中怎麼保證運行的流暢性

把耗時操作寫入子線程中(如網絡請求,SQL數據查詢語句)

MVC 、MVP

MVC耦合性低,減少了模塊代碼之間的相互影響,可擴展性好,模塊指責劃分明確,降低BUG的出現率,利於代碼的維護
VIEW相當於XML
MVP使MODEL跟VIEW達到完全解耦,並且這裏的VIEW相當於Fragment和Activity,MODEL跟VIEW分別提供接口,讓Presenter把VIEW跟MODEL連接起來,所有的交互都發生在Presenter內部,而在MVC中View會直接從Model中讀取數據而不是通過 Controller。

WebView和JS互調

版本適配 兼容jar包

怎麼在一個程序中啓動其他的程序

APP的性能優化

1、如何對 Android 應用進行性能分析
一款 App 流暢與否安裝在自己的真機裏,玩幾天就能有個大概的感性認識。不過通過專業的分析工
具可以使我們更好的分析我們的應用。而在實際開發中,我們解決完當前應用所有 bug 後,就會開
始考慮到新能的優化。
如果不考慮使用其他第三方性能分析工具的話,我們可以直接使用 ddms 中的工具,其實 ddms 工
具已經非常的強大了。ddms 中有 traceview、heap、allocation tracker 等工具都可以幫助我們分
析應用的方法執行時間效率和內存使用情況。

一:traceview
二:heap
三:allocation tracker

什麼情況下會導致內存泄露

OOM 內存溢出,想要避免 OOM 異常首先我們要知道什麼情況下會導致 OOM 異常。
1、圖片過大導致 OOM

Android 中用 bitmap 時很容易內存溢出,比如報如下錯誤:Java.lang.OutOfMemoryError :
bitmap size exceeds VM budget。
解決方法:方法 1: 等比例縮小圖片
BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 2;
    //Options 只保存圖片尺寸大小,不保存圖片到內存
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inSampleSize = 2;
    Bitmap bmp = null;
    bmp = BitmapFactory.decodeResource(getResources(),
    mImageIds[position],opts);
    //回收
    bmp.recycle();//
以上代碼可以優化內存溢出,但它只是改變圖片大小,並不能徹底解決內存溢出。

方法 2:對圖片採用軟引用,及時地進行 recyle()操作

SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap);
    if(bitmap != null){
    if(bitmap.get() != null && !bitmap.get().isRecycled()){
    bitmap.get().recycle();
    bitmap = null;
    }
    }

方法 3:使用加載圖片框架處理圖片,如專業處理加載圖片的 ImageLoader 圖片加載框架。還有我
們學的 XUtils 的 BitMapUtils 來做處理。

2、界面切換導致 OOM

一般情況下,開發中都會禁止橫屏的。因爲如果是來回切換話,activity 的生命週期會重新銷燬
然後創建。
有時候我們會發現這樣的問題,橫豎屏切換 N 次後 OOM 了。
這種問題沒有固定的解決方法,但是我們可以從以下幾個方面下手分析。

1、看看頁面佈局當中有沒有大的圖片,比如背景圖之類的。
去除 xml 中相關設置,改在程序中設置背景圖(放在 onCreate()方法中):

Drawable drawable = getResources().getDrawable(R.drawable.id);
        ImageView imageView = new ImageView(this);
        imageView.setBackgroundDrawable(drawable);
在 Activity destory 時注意,drawable.setCallback(null); 防止 Activity 得不到及時的釋放。

2、跟上面方法相似,直接把 xml 配置文件加載成 view 再放到一個容器裏,然後直接調用
this.setContentView(View view);方法,避免 xml 的重複加載。

3、 在頁面切換時儘可能少地重複使用一些代碼
比如:重複調用數據庫,反覆使用某些對象等等……

4、查詢數據庫沒有關閉遊標

程序中經常會進行查詢數據庫的操作,但是經常會有使用完畢 Cursor 後沒有關閉的情況。如果
我們的查詢結果集比較小,對內存的消耗不容易被發現,只有在常時間大量操作的情況下才會出現內
存問題,這樣就會給以後的測試和問題排查帶來困難和風險。

5、構造 Adapter 時,沒有使用緩存的 convertView

在使用 ListView 的時候通常會使用 Adapter,那麼我們應該儘可能的使用 ConvertView。
爲什麼要使用 convertView?
當 convertView 爲空時,用 setTag()方法爲每個 View 綁定一個存放控件的 ViewHolder 對象。
當 convertView 不爲空,重複利用已經創建的 view 的時候,使用 getTag()方法獲取綁定的
ViewHolder 對象,這樣就避免了 findViewById 對控件的層層查詢,而是快速定位到控件。
5、Bitmap 對象不再使用時調用 recycle()釋放內存
有時我們會手工的操作 Bitmap 對象,如果一個 Bitmap 對象比較佔內存,當它不再被使用的時
候,可以調用 Bitmap.recycle()方法回收此對象的像素所佔用的內存,但這不是必須的,視情況而定。
6、其他
Android 應用程序中最典型的需要注意釋放資源的情況是在 Activity 的生命週期中,在
onPause()、onStop()、 onDestroy()方法中需要適當的釋放資源的情況。使用廣播沒有註銷也會產
生 OOM。

如何避免 OOM 異常

OOM 內存溢出,想要避免 OOM 異常首先我們要知道什麼情況下會導致 OOM 異常。

一:圖片過大導致內存溢出
二:界面切換導致 OOM
三:查詢數據庫沒有關閉遊標
四:構造 Adapter 時,沒有使用緩存的 convertView
五:Bitmap 對象不再使用時調用 recycle()釋放內存
六:其他
Android 應用程序中最典型的需要注意釋放資源的情況是在 Activity 的生命週期中,在
onPause()、onStop()、 onDestroy()方法中需要適當的釋放資源的情況。使用廣播沒有註銷也會產
生 OOM。

線程間的通信(有幾種方式)

一:共享內存(變量);
二:文件,數據庫;
三:Handler;
四:Java 裏的 wait(),notify(),notifyAll()

JNI怎麼調用,原理

============================

Android基礎

四大組件:activity server broadcast contentprovider

Android高級

Android新技術

網絡請求:RxJava + Retrofit RxAndroid RxEventBus
圖片框架:Glide

JNI和NDK

Android架構

Android第三方框架

性能優化

發佈了29 篇原創文章 · 獲贊 9 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章