天天看點

整理最全的Android開發工程師面試題,面試題詳解。java、Android程式員

1.    請描述下Activity的生命周期。
必調用的三個方法:onCreate()--> onStart() --> onResume(),用AAA表示
(1)父Activity啟動子Activity,子Actvity退出,父Activity調用順序如下
 AAA --> onFreeze() --> onPause() --> onStop() --> onRestart()--> onStart(),onResume() …
(2)使用者點選Home,Actvity調用順序如下
 AAA --> onFreeze() --> onPause() --> onStop() -- Maybe -->onDestroy() – Maybe
(3)調用finish(), Activity調用順序如下
 AAA --> onPause() --> onStop() --> onDestroy()
(4)在Activity上顯示dialog, Activity調用順序如下
 AAA
(5)在父Activity上顯示透明的或非全屏的activity,Activity調用順序如下
 AAA --> onFreeze() --> onPause()
(6)裝置進入睡眠狀态,Activity調用順序如下
 AAA --> onFreeze() --> onPause()2.    如果背景的Activity由于某原因被系統回收了,如何在被系統回收之前儲存目前狀态?
onSaveInstanceState()
當你的程式中某一個ActivityA在運作時,主動或被動地運作另一個新的Activity B,這個時候A會執行onSaveInstanceState()。B完成以後又會來找A,這個時候就有兩種情況:一是A被回收,二是A沒有被回收,被回收的A就要重新調用onCreate()方法,不同于直接啟動的是這回onCreate()裡是帶上了參數savedInstanceState;而沒被收回的就直接執行onResume(),跳過onCreate()了。
3.    如何将一個Activity設定成視窗的樣式。
在AndroidManifest.xml 中定義Activity的地方一句話android:theme="@android:style/Theme.Dialog"或android:theme="@android:style/Theme.Translucent"就變成半透明的
4.    如何退出Activity?如何安全退出已調用多個Activity的Application?
對于單一Activity的應用來說,退出很簡單,直接finish()即可。
當然,也可以用killProcess()和System.exit()這樣的方法。

但是,對于多Activity的應用來說,在打開多個Activity後,如果想在最後打開的Activity直接退出,上邊的方法都是沒有用的,因為上邊的方法都是結束一個Activity而已。
當然,網上也有人說可以。
就好像有人問,在應用裡如何捕獲Home鍵,有人就會說用keyCode比較KEYCODE_HOME即可,而事實上如果不修改framework,根本不可能做到這一點一樣。
 是以,最好還是自己親自試一下。

 那麼,有沒有辦法直接退出整個應用呢?
 在2.1之前,可以使用ActivityManager的restartPackage方法。
 它可以直接結束整個應用。在使用時需要權限android.permission.RESTART_PACKAGES。
 注意不要被它的名字迷惑。

 可是,在2.2,這個方法失效了。
 在2.2添加了一個新的方法,killBackgroundProcesses(),需要權限 android.permission.KILL_BACKGROUND_PROCESSES。
 可惜的是,它和2.2的restartPackage一樣,根本起不到應有的效果。

 另外還有一個方法,就是系統自帶的應用程式管理裡,強制結束程式的方法,forceStopPackage()。
 它需要權限android.permission.FORCE_STOP_PACKAGES。
 并且需要添加android:sharedUserId="android.uid.system"屬性
 同樣可惜的是,該方法是非公開的,他隻能運作在系統程序,第三方程式無法調用。
 因為需要在Android.mk中添加LOCAL_CERTIFICATE:= platform。
 而Android.mk是用于在Android源碼下編譯程式用的。

 從以上可以看出,在2.2,沒有辦法直接結束一個應用,而隻能用自己的辦法間接辦到。

 現提供幾個方法,供參考:

 1、抛異常強制退出:
 該方法通過抛異常,使程式Force Close。
 驗證可以,但是,需要解決的問題是,如何使程式結束掉,而不彈出Force Close的視窗。

 2、記錄打開的Activity:
 每打開一個Activity,就記錄下來。在需要退出時,關閉每一個Activity即可。

 3、發送特定廣播:
 在需要結束應用時,發送一個特定的廣播,每個Activity收到廣播後,關閉即可。

 4、遞歸退出
 在打開新的Activity時使用startActivityForResult,然後自己加标志,在onActivityResult中處理,遞歸關閉。

 除了第一個,都是想辦法把每一個Activity都結束掉,間接達到目的。
 但是這樣做同樣不完美。
 你會發現,如果自己的應用程式對每一個Activity都設定了nosensor,在兩個Activity結束的間隙,sensor可能有效了。
 但至少,我們的目的達到了,而且沒有影響使用者使用。

 為了程式設計友善,最好定義一個Activity基類,處理這些共通問題。 5.    請介紹下Android中常用的五種布局。
FrameLayout(架構布局),LinearLayout (線性布局),AbsoluteLayout(絕對布局),RelativeLayout(相對布局),TableLayout(表格布局)
6.    請介紹下Android的資料存儲方式。
一.SharedPreferences方式
二.檔案存儲方式
三.SQLite資料庫方式
四.内容提供器(Contentprovider)方式
五.  網絡存儲方式
7.    請介紹下ContentProvider是如何實作資料共享的。
建立一個屬于你自己的Content provider或者将你的資料添加到一個已經存在的Content provider中,前提是有相同資料類型并且有寫入Content provider的權限。
8.   如何啟用Service,如何停用Service。
 
Android中的service類似于windows中的service,service一般沒有使用者操作界面,它運作于系統中不容易被使用者發覺,
可以使用它開發如監控之類的程式。
一。步驟
第一步:繼承Service類
publicclass SMSService extends Service { }
第二步:在AndroidManifest.xml檔案中的<application>節點裡對服務進行配置:
<serviceandroid:name=".DemoService" />
二。Context.startService()和Context.bindService
服務不能自己運作,需要通過調用Context.startService()或Context.bindService()方法啟動服務。這兩個方法都可
以啟動Service,但是它們的使用場合有所不同。
1.使用startService()方法啟用服務,調用者與服務之間沒有關連,即使調用者退出了,服務仍然運作。
使用bindService()方法啟用服務,調用者與服務綁定在了一起,調用者一旦退出,服務也就終止。
2.采用Context.startService()方法啟動服務,在服務未被建立時,系統會先調用服務的onCreate()方法,
接着調用onStart()方法。如果調用startService()方法前服務已經被建立,多次調用startService()方法并
不會導緻多次建立服務,但會導緻多次調用onStart()方法。
采用startService()方法啟動的服務,隻能調用Context.stopService()方法結束服務,服務結束時會調用
onDestroy()方法。 
  3.采用Context.bindService()方法啟動服務,在服務未被建立時,系統會先調用服務的onCreate()方法,
接着調用onBind()方法。這個時候調用者和服務綁定在一起,調用者退出了,系統就會先調用服務的onUnbind()方法,
。接着調用onDestroy()方法。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法并不會
導緻多次建立服務及綁定(也就是說onCreate()和onBind()方法并不會被多次調用)。如果調用者希望與正在綁定的服務
解除綁定,可以調用unbindService()方法,調用該方法也會導緻系統調用服務的onUnbind()-->onDestroy()方法。
三。Service的生命周期
1.Service常用生命周期回調方法如下:
 onCreate() 該方法在服務被建立時調用,該方法隻會被調用一次,無論調用多少次startService()或bindService()方法,
服務也隻被建立一次。 onDestroy()該方法在服務被終止時調用。 
  2.Context.startService()啟動Service有關的生命周期方法
onStart()隻有采用Context.startService()方法啟動服務時才會回調該方法。該方法在服務開始運作時被調用。
多次調用startService()方法盡管不會多次建立服務,但onStart() 方法會被多次調用。
 3. Context.bindService()啟動Service有關的生命周期方法
onBind()隻有采用Context.bindService()方法啟動服務時才會回調該方法。該方法在調用者與服務綁定時被調用,
當調用者與服務已經綁定,多次調用Context.bindService()方法并不會導緻該方法被多次調用。
onUnbind()隻有采用Context.bindService()方法啟動服務時才會回調該方法。該方法在調用者與服務解除綁定時被調用。
備注:
1. 采用startService()啟動服務
     Intent intent = newIntent(DemoActivity.this, DemoService.class);
     startService(intent);
2.Context.bindService()啟動
    Intent intent = newIntent(DemoActivity.this, DemoService.class);
    bindService(intent, conn,Context.BIND_AUTO_CREATE);
   //unbindService(conn);//解除綁定
 
9.   注冊廣播有幾種方式,這些方式有何優缺點?請談談Android引入廣播機制的用意。
  Android廣播機制(兩種注冊方法)
在android下,要想接受廣播資訊,那麼這個廣播接收器就得我們自己來實作了,我們可以繼承BroadcastReceiver,就可以有一個廣播接受器了。有個接受器還不夠,我們還得重寫BroadcastReceiver裡面的onReceiver方法,當來廣播的時候我們要幹什麼,這就要我們自己來實作,不過我們可以搞一個資訊防火牆。具體的代碼:
 
public class SmsBroadCastReceiver extendsBroadcastReceiver    
{   
  
    @Override  
    public voidonReceive(Context context, Intent intent)  
    {   
        Bundlebundle = intent.getExtras();   
        Object[]object = (Object[])bundle.get("pdus");   
        SmsMessagesms[]=new SmsMessage[object.length];   
        for(int i=0;i<object.length;i++)   
        {   
            sms[0]= SmsMessage.createFromPdu((byte[])object[i]);  
           Toast.makeText(context, "來自"+sms[i].getDisplayOriginatingAddress()+"的消息是:"+sms[i].getDisplayMessageBody(),Toast.LENGTH_SHORT).show();   
        }   
        //終止廣播,在這裡我們可以稍微處理,根據使用者輸入的号碼可以實作短信防火牆。   
       abortBroadcast();   
    }   
       
}  
 
  當實作了廣播接收器,還要設定廣播接收器接收廣播資訊的類型,這裡是資訊:android.provider.Telephony.SMS_RECEIVED
 
  我們就可以把廣播接收器注冊到系統裡面,可以讓系統知道我們有個廣播接收器。這裡有兩種,一種是代碼動态注冊:
 
//生成廣播處理   
smsBroadCastReceiver = new SmsBroadCastReceiver();   
//執行個體化過濾器并設定要過濾的廣播   
 
IntentFilter intentFilter = newIntentFilter("android.provider.Telephony.SMS_RECEIVED"); 
 
//注冊廣播   
BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver,intentFilter);  
一種是在AndroidManifest.xml中配置廣播
 
<?xml version="1.0"encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
     package="spl.broadCastReceiver"  
     android:versionCode="1" 
     android:versionName="1.0"> 
    <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> 
        <activityandroid:name=".BroadCastReceiverActivity"  
                 android:label="@string/app_name">  
           <intent-filter>  
               <action android:name="android.intent.action.MAIN"/>  
               <category android:name="android.intent.category.LAUNCHER"/>  
           </intent-filter>  
       </activity>  
           
        <!--廣播注冊--> 
       <receiver android:name=".SmsBroadCastReceiver">  
           <intent-filter android:priority="20">  
               <action android:name="android.provider.Telephony.SMS_RECEIVED"/>  
           </intent-filter>  
       </receiver>  
           
   </application>  
       
    <uses-sdkandroid:minSdkVersion="7" /> 
       
    <!-- 權限申請 --> 
   <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>  
       
</manifest>  
 
  兩種注冊類型的差別是:
 
     1)第一種不是常駐型廣播,也就是說廣播跟随程式的生命周期。
 
     2)第二種是常駐型,也就是說當應用程式關閉後,如果有資訊廣播來,程式也會被系統調用自動運作。
10.   請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關系。
 
Handler簡介:
一個Handler允許你發送和處理Message和Runable對象,這些對象和一個線程的MessageQueue相關聯。每一個線程執行個體和一個單獨的線程以及該線程的MessageQueue相關聯。當你建立一個新的Handler時,它就和建立它的線程綁定在一起了。這裡,線程我們也可以了解為線程的MessageQueue。從這一點上來看,Handler把Message和Runable對象傳遞給MessageQueue,而且在這些對象離開MessageQueue時,Handler負責執行他們。

 Handler有兩個主要的用途:(1)确定在将來的某個時間點執行一個或者一些Message和Runnable對象。(2)在其他線程(不是Handler綁定線程)中排入一些要執行的動作。

 Scheduling Message,即(1),可以通過以下方法完成:
 post(Runnable):Runnable在handler綁定的線程上執行,也就是說不建立新線程。
 postAtTime(Runnable,long):
 postDelayed(Runnable,long):
 sendEmptyMessage(int):
 sendMessage(Message):
 sendMessageAtTime(Message,long):
 sendMessageDelayed(Message,long):
 post這個動作讓你把Runnable對象排入MessageQueue,MessageQueue受到這些消息的時候執行他們,當然以一定的排序。sendMessage這個動作允許你把Message對象排成隊列,這些Message對象包含一些資訊,Handler的hanlerMessage(Message)會處理這些Message.當然,handlerMessage(Message)必須由Handler的子類來重寫。這是程式設計人員需要作的事。

當posting或者sending到一個Hanler時,你可以有三種行為:當MessageQueue準備好就處理,定義一個延遲時間,定義一個精确的時間去處理。後兩者允許你實作timeout,tick,和基于時間的行為。

當你的應用建立一個新的程序時,主線程(也就是UI線程)自帶一個MessageQueue,這個MessageQueue管理頂層的應用對象(像activities,broadcast receivers等)和主線程建立的窗體。你可以建立自己的線程,并通過一個Handler和主線程進行通信。這和之前一樣,通過post和sendmessage來完成,差别在于在哪一個線程中執行這麼方法。在恰當的時候,給定的Runnable和Message将在Handler的MessageQueue中被Scheduled。


 Message簡介:
 Message類就是定義了一個資訊,這個資訊中包含一個描述符和任意的資料對象,這個資訊被用來傳遞給Handler.Message對象提供額外的兩個int域和一個Object域,這可以讓你在大多數情況下不用作配置設定的動作。
盡管Message的構造函數是public的,但是擷取Message執行個體的最好方法是調用Message.obtain(),或者Handler.obtainMessage()方法,這些方法會從回收對象池中擷取一個。


 MessageQueue簡介:
這是一個包含message清單的底層類。Looper負責分發這些message。Messages并不是直接加到一個MessageQueue中,而是通過MessageQueue.IdleHandler關聯到Looper。
你可以通過Looper.myQueue()從目前線程中擷取MessageQueue。


 Looper簡介:
 Looper類被用來執行一個線程中的message循環。預設情況,沒有一個消息循環關聯到線程。線上程中調用prepare()建立一個Looper,然後用loop()來處理messages,直到循環終止。

大多數和messageloop的互動是通過Handler。

下面是一個典型的帶有Looper的線程實作。
   class LooperThread extends Thread {
       public Handler mHandler;
       
       public void run() {
           Looper.prepare();
           
           mHandler = new Handler() {
               public voidhandleMessage(Message msg) {
                   // process incomingmessages here
               }
           };
           
           Looper.loop();
       }
   } 
 
11.   AIDL的全稱是什麼?如何工作?能處理哪些類型的資料?
 
AIDL的英文全稱是Android Interface DefineLanguage
當A程序要去調用B程序中的service時,并實作通信,我們通常都是通過AIDL來操作的
A工程:
首先我們在net.blogjava.mobile.aidlservice包中建立一個RemoteService.aidl檔案,在裡面我們自定義一個接口,含有方法get。ADT插件會在gen目錄下自動生成一個RemoteService.java檔案,該類中含有一個名為RemoteService.stub的内部類,該内部類中含有aidl檔案接口的get方法。
說明一:aidl檔案的位置不固定,可以任意
然後定義自己的MyService類,在MyService類中自定義一個内部類去繼承RemoteService.stub這個内部類,實作get方法。在onBind方法中傳回這個内部類的對象,系統會自動将這個對象封裝成IBinder對象,傳遞給他的調用者。
其次需要在AndroidManifest.xml檔案中配置MyService類,代碼如下:
<!-- 注冊服務 -->  
<service android:name=".MyService"> 
  <intent-filter> 
  <!--  指定調用AIDL服務的ID  --> 
      <actionandroid:name="net.blogjava.mobile.aidlservice.RemoteService" /> 
   </intent-filter> 
</service>
為什麼要指定調用AIDL服務的ID,就是要告訴外界MyService這個類能夠被别的程序通路,隻要别的程序知道這個ID,正是有了這個ID,B工程才能找到A工程實作通信。
說明:AIDL并不需要權限
B工程:
      首先我們要将A工程中生成的RemoteService.java檔案拷貝到B工程中,在bindService方法中綁定aidl服務
      綁定AIDL服務就是将RemoteService的ID作為intent的action參數。
      說明:如果我們單獨将RemoteService.aidl檔案放在一個包裡,那個在我們将gen目錄下的該包拷貝到B工程中。如果我們将RemoteService.aidl檔案和我們的其他類存放在一起,那麼我們在B工程中就要建立相應的包,以保證RmoteService.java檔案的報名正确,我們不能修改RemoteService.java檔案
          bindService(newInten("net.blogjava.mobile.aidlservice.RemoteService"),serviceConnection, Context.BIND_AUTO_CREATE); 
      ServiceConnection的onServiceConnected(ComponentNamename, IBinder service)方法中的service參數就是A工程中MyService類中繼承了RemoteService.stub類的内部類的對象。
 
12.    請解釋下Android程式運作時權限與檔案系統權限的差別。
 
13.    系統上安裝了多種浏覽器,能否指定某浏覽器通路指定頁面?請說明原由。
 
14.    有一個一維整型數組int[]data儲存的是一張寬為width,高為height的圖檔像素值資訊。請寫一個算法,将該圖檔所有的白色不透明(0xffffffff)像素點的透明度調整為50%。
 
15.    你如何評價Android系統?優缺點。      

繼續閱讀