android 面試題

 真他媽的全面呢。
1.    請描述下Activity的生命週期。
2.    如果後臺的Activity由於某原因被系統回收了,如何在被系統回收之前保存當前狀態?
3.    如何將一個Activity設置成窗口的樣式。(Edited by Sodino)
4.    如何退出Activity?如何安全退出已調用多個Activity的Application?
5.    請介紹下Android中常用的五種佈局。
6.    請介紹下Android的數據存儲方式。(Edited by Sodino)
7.    請介紹下ContentProvider是如何實現數據共享的。(Edited by Sodino)
8.    如何啓用Service,如何停用Service。(Edited by Sodino)
9.    註冊廣播有幾種方式,這些方式有何優缺點?請談談Android引入廣播機制的用意。
10.    請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關係。
11.    AIDL的全稱是什麼?如何工作?能處理哪些類型的數據?
12.    請解釋下Android程序運行時權限與文件系統權限的區別。(Edited by Sodino)
13.    系統上安裝了多種瀏覽器,能否指定某瀏覽器訪問指定頁面?請說明原由。
14.    有一個一維整型數組int[]data保存的是一張寬爲width,高爲height的圖片像素值信息。請寫一個算法,將該圖片所有的白色不透明(0xffffffff)像素點的透明度調整爲50%15.    你如何評價Android系統?優缺點。


1.    請描述下Activity的生命週期


http://weizhulin.blog.51cto.com/1556324/311495

詳細介紹一下這幾個方法中系統在做什麼以及我們應該做什麼:

   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]來處理多線程和界面交互的問題。這個我後面會講一些,最近因爲這些東西頭已經很大了,等我理清思緒再跟大家分享。


2.    如果後臺的Activity由於某原因被系統回收了,如何在被系統回收之前保存當前狀態?
當你的程序中某一個Activity A 在運行時中,主動或被動地運行另一個新的Activity B 

這個時候A會執行

Java代碼


 

  1. public 
  2. void onSaveInstanceState(Bundle outState) {     
  3.     super.onSaveInstanceState(outState);     
  4.     outState.putLong("id"1234567890);     
  5. }     
  6.  
  7. public void onSaveInstanceState(Bundle outState) {    super.onSaveInstanceState(outState);    outState.putLong("id"1234567890);}  
  8.  


B 完成以後又會來找A, 這個時候就有兩種情況,一種是A被回收,一種是沒有被回收,被回
收的A就要重新調用onCreate()方法,不同於直接啓動的是這回onCreate()裏是帶上參數
savedInstanceState,沒被收回的就還是onResume就好了。

savedInstanceState是一個Bundle對象,你基本上可以把他理解爲系統幫你維護的一個Map對象。在onCreate()裏你可能會用到它,如果正常啓動onCreate就不會有它,所以用的時候要判斷一下是否爲空。

Java代碼


if(savedInstanceState != null){  
     long id = savedInstanceState.getLong("id");  
}  

if(savedInstanceState != null){     long id = savedInstanceState.getLong("id");}


就像官方的Notepad教程裏的情況,你正在編輯某一個note,突然被中斷,那麼就把這個note的id記住,再起來的時候就可以根據這個id去把那個note取出來,程序就完整一些。這也是看你的應用需不需要保存什麼,比如你的界面就是讀取一個列表,那就不需要特殊記住什麼,哦,沒準你需要記住滾動條的位置...

3.    如何將一個Activity設置成窗口的樣式
簡單你只需要設置 一下Activity的主題就可以了在AndroidManifest.xml 中定義 Activity的
地方一句話:


Xml代碼


 

  1. android :theme="@android:style/Theme.Dialog"   
  2.  
  3. android:theme="@android:style/Theme.Dialog"   
  4.  


這就使你的應用程序變成對話框的形式彈出來了,或者


Xml代碼


 

  1. android:theme="@android:style/Theme.Translucent"   
  2.  
  3. android:theme="@android:style/Theme.Translucent"   
  4.  

就變成半透明的,[友情提示-.-]類似的這種activity的屬性可以在android.R.styleable 類的AndroidManifestActivity 方法中看到,AndroidManifest.xml中所有元素的屬性的介紹都可以參考這個類android.R.styleable

上面說的是屬性名稱,具體有什麼值是在android.R.style中可以看到,比如這個"@android:style/Theme.Dialog" 就對應於android.R.style.Theme_Dialog ,('_'換成'.' <--注意:這個是文章內容不是笑臉)就可以用在描述文件中了,找找類定義和描述文件中的對應關係就都明白了。

4.    如何退出Activity
對於單一Activity的應用來說,退出很簡單,直接finish()即可。
當然,也可以用killProcess()和System.exit()這樣的方法。 現提供幾個方法,供參考:

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

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

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

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

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

爲了編程方便,最好定義一個Activity基類,處理這些共通問題。 5.請介紹下Android中常用的五種佈局 Android佈局是應用界面開發的重要一環,在Android中,共有五種佈局方式,分別是:FrameLayout(框架布 局),LinearLayout (線性佈局),AbsoluteLayout(絕對佈局),RelativeLayout(相對佈局),TableLayout(表格佈局)。
   
    一、FrameLayout
   
    這個佈局可以看成是牆腳堆東西,有一個四方的矩形的左上角牆腳,我們放了第一個東西,要再放一個,那就在放在原來放的位置的上面,這樣依次的放,會蓋住原來的東西。這個佈局比較簡單,也只能放一點比較簡單的東西。
   
    二、LinearLayout
   
    線性佈局,這個東西,從外框上可以理解爲一個div,他首先是一個一個從上往下羅列在屏幕上。每一個LinearLayout裏面又可分爲垂直佈局 (android:orientation="vertical")和水平佈局(android:orientation="horizontal" )。當垂直佈局時,每一行就只有一個元素,多個元素依次垂直往下;水平佈局時,只有一行,每一個元素依次向右排列。
   
    linearLayout中有一個重要的屬性 android:layout_weight="1",這個weight在垂直佈局時,代表行距;水平的時候代表列寬;weight值越大就越大。
   
    三、AbsoluteLayout
   
    絕對佈局猶如div指定了absolute屬性,用X,Y座標來指定元素的位置android:layout_x="20px" android:layout_y="12px" 這種佈局方式也比較簡單,但是在垂直隨便切換時,往往會出問題,而且多個元素的時候,計算比較麻煩。
   
    四、RelativeLayout
   
    相對佈局可以理解爲某一個元素爲參照物,來定位的佈局方式。主要屬性有:
   
    相對於某一個元素
   
    android:layout_below="@id/aaa" 該元素在 id爲aaa的下面
   
    android:layout_toLeftOf="@id/bbb" 改元素的左邊是bbb
   
    相對於父元素的地方
   
    android:layout_alignParentLeft="true"  在父元素左對齊
   
    android:layout_alignParentRight="true" 在父元素右對齊
   
    還可以指定邊距等,具體詳見API
   
    五。TableLayout
   
    表格佈局類似Html裏面的Table。每一個TableLayout裏面有表格行TableRow,TableRow裏面可以具體定義每一個元素,設定他的對齊方式 android:gravity="" 。
   
    每一個佈局都有自己適合的方式,另外,這五個佈局元素可以相互嵌套應用,做出美觀的界面。 6. 請介紹下Android的數據存儲方式

Android 提供了5種方式存儲數據:
--使用SharedPreferences存儲數據;
--文件存儲數據;
--SQLite數據庫存儲數據;
--使用ContentProvider存儲數據;
--網絡存儲數據;

先 說下,Preference,File, DataBase這三種方式分別對應的目錄是/data/data/Package Name/Shared_Pref, /data/data/Package Name/files, /data/data/Package Name/database 。

在Android中通常使用File存儲方式是用 Context.openFileOutput(String fileName, int mode)和Context.openFileInput(String fileName)。
Context.openFileOutput(String fileName, int mode)生成的文件自動存儲在/data/data/Package Name/files目錄下,其全路徑是/data/data/Package Name/files/fileName 。注意下,這裏的參數fileName不可以包含路徑分割符(如"/")。
通常來說,這種方式生成的文件只能在這個apk內訪問。但這個結論是指使用Context.openFileInput(String fileName)的方式。使用這種方式,每個apk只可以訪問自己的/data/data/Package Name/files目錄下的文件,原因很簡單,參數fileName中不可以包含路徑分割符,Android會自動在/data/data /Package Name/files目錄下尋找文件名爲fileName的文件。

一:使用SharedPreferences存儲數據

首先說明SharedPreferences存儲方式,它是 Android提供的用來存儲一些簡單配置信息的一種機制,例如:登錄用戶的用戶名與密碼。其採用了Map數據結構來存儲數據,以鍵值的方式存儲,可以簡單的讀取與寫入,具體實例如下:
void ReadSharedPreferences(){
String strName,strPassword;
SharedPreferences   user = getSharedPreferences(“user_info”,0);
strName = user.getString(“NAME”,””);
strPassword = user getString(“PASSWORD”,””);
}
void WriteSharedPreferences(String strName,String strPassword){
SharedPreferences   user = getSharedPreferences(“user_info”,0);
uer.edit();
user.putString(“NAME”, strName);
user.putString(“PASSWORD” ,strPassword);
user.commit();
}
數據讀取與寫入的方法都非常簡單,只是在寫入的時候有些區別:先調用edit()使其處於編輯狀態,然後才能修改數據,最後使用commit()提交修改的數據。實際上SharedPreferences是採用了XML格式將數據存儲到設備中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的數據存儲結果爲例,打開後可以看到一個user_info.xml的文件,打開後可以看到:
<?xml version=”1.0″ encoding=”UTF-8″?>
<map>
<string name=”NAME”>moandroid</string>
<string name=” PASSWORD”>SharedPreferences</string>
</map>
使用SharedPreferences是有些限制的:只能在同一個包內使用,不能在不同的包之間使用。

二:文件存儲數據

 


文件存儲方式是一種較常用的方法,在Android中讀取/寫入文件的方法,與 Java中實現I/O的程序是完全一樣的,提供了openFileInput()和openFileOutput()方法來讀取設備上的文件。 FilterInputStream, FilterOutputStream等可以到Java io package說明中去詳細學習,不再此詳細說明,具體實例如下:
String fn = “moandroid.log”;
FileInputStream fis = openFileInput(fn);
FileOutputStream fos = openFileOutput(fn,Context.MODE_PRIVATE);
除此之外,Android還提供了其他函數來操作文件,詳細說明請閱讀Android SDK。


三:網絡存儲數據


網絡存儲方式,需要與Android 網絡數據包打交道,關於Android 網絡數據包的詳細說明,請閱讀Android SDK引用了Java SDK的哪些package?。

四:ContentProvider

1、ContentProvider簡介


當應用繼承ContentProvider類,並重寫該類用於提供數據和存儲數據的方法,就可以向其他應用共享其數據。雖然使用其他方法也可以對外共享數據,但數據訪問方式會因數據存儲的方式而不同,如:採用文件方式對外共享數據,需要進行文件操作讀寫數據;採用sharedpreferences共享數據,需要使用sharedpreferences API讀寫數據。而使用ContentProvider共享數據的好處是統一了數據訪問方式。?

2、Uri類簡介


Uri代表了要操作的數據,Uri主要包含了兩部分信息:1.需要操作的ContentProvider ,2.對ContentProvider中的什麼數據進行操作,一個Uri由以下幾部分組成:
1.scheme:ContentProvider(內容提供者)的scheme已經由Android所規定爲:content://。


2.主機名(或Authority):用於唯一標識這個ContentProvider,外部調用者可以根據這個標識來找到它。


3.路徑(path):可以用來表示我們要操作的數據,路徑的構建應根據業務而定,如下:
? 要操作contact表中id爲10的記錄,可以構建這樣的路徑:/contact/10
? 要操作contact表中id爲10的記錄的name字段, contact/10/name
? 要操作contact表中的所有記錄,可以構建這樣的路徑:/contact?
要操作的數據不一定來自數據庫,也可以是文件等他存儲方式,如下:
要操作xml文件中contact節點下的name節點,可以構建這樣的路徑:/contact/name
如果要把一個字符串轉換成Uri,可以使用Uri類中的parse()方法,如下:
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
3、UriMatcher、ContentUrist和ContentResolver簡介

因爲Uri代表了要操作的數據,所以我們很經常需要解析Uri,並從 Uri中獲取數據。Android系統提供了兩個用於操作Uri的工具類,分別爲UriMatcher 和ContentUris 。掌握它們的使用,會便於我們的開發工作。
? UriMatcher:用於匹配Uri,它的用法如下:


1.首先把你需要匹配Uri路徑全部給註冊上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼(-1)。
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider /contact路徑,返回匹配碼爲1
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就會返回匹配碼
//如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路徑,返回匹配碼爲2
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#號爲通配符

2.註冊完需要匹配的Uri後,就可以使用uriMatcher.match(uri)方法對輸入的Uri進行匹配,如果匹配就返回匹配碼,匹配碼是調用 addURI()方法傳入的第三個參數,假設匹配 content://com.changcheng.sqlite.provider.contactprovider/contact路徑,返回的匹配碼爲1。
?
ContentUris:用於獲取Uri路徑後面的ID部分,它有兩個比較實用的方法:
? withAppendedId(uri, id)用於爲路徑加上ID部分
? parseId(uri)方法用於從路徑中獲取ID部分
? ContentResolver:當外部應用需要對ContentProvider中的數據進行添加、刪除、修改和查詢操作時,可以使用 ContentResolver 類來完成,要獲取ContentResolver 對象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,來操作數據。

五:總結說明


以上5中存儲方式,在以後的開發過程中,根據設計目標、性能需求、空間需求等找到合適的數據存儲方式。Android 中的數據存儲都是私有的,其他應用程序都是無法訪問的,除非通過ContentResolver獲取其他程序共享的數據。採用文件方式對外共享數據,需要進行文件操作讀寫數據;採用sharedpreferences共享數據,需要使用sharedpreferences API讀寫數據。而使用ContentProvider共享數據的好處是統一了數據訪問方式。

8.如何啓用Service,如何停用Service

Android中的服務和windows中的服務是類似的東西,服務一般沒有用戶操作界面,它運行於系統中不容易被用戶發覺,可以使用它開發如監控之類的程序。服務的開發比較簡單,如下:

第一步:繼承Service

public class SMSService extends Service {

}

第二步:在AndroidManifest.xml文件中的<application>節點裏對服務進行配置:

<service android:name=".SMSService" />

 

服務不能自己運行,需要通過調用Context.startService()Context.bindService()方法啓動服務。這兩個方法都可以啓動Service,但是它們的使用場合有所不同。使用startService()方法啓用服務,調用者與服務之間沒有關連,即使調用者退出了,服務仍然運行。使用bindService()方法啓用服務,調用者與服務綁定在了一起,調用者一旦退出,服務也就終止,大有“不求同時生,必須同時死”的特點。

 

如果打算採用Context.startService()方法啓動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,接着調用onStart()方法。如果調用startService()方法前服務已經被創建,多次調用startService()方法並不會導致多次創建服務,但會導致多次調用onStart()方法。採用startService()方法啓動的服務,只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。

 

如果打算採用Context.bindService()方法啓動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,接着調用onBind()方法。這個時候調用者和服務綁定在一起,調用者退出了,系統就會先調用服務的onUnbind()方法,接着調用onDestroy()方法。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法並不會導致多次創建服務及綁定(也就是說onCreate()onBind()方法並不會被多次調用)。如果調用者希望與正在綁定的服務解除綁定,可以調用unbindService()方法,調用該方法也會導致系統調用服務的onUnbind()-->onDestroy()方法。

服務常用生命週期回調方法如下:

onCreate() 該方法在服務被創建時調用,該方法只會被調用一次,無論調用多少次startService()bindService()方法,服務也只被創建一次。

onDestroy()該方法在服務被終止時調用。

 

與採用Context.startService()方法啓動服務有關的生命週期方法

onStart() 只有採用Context.startService()方法啓動服務時纔會回調該方法。該方法在服務開始運行時被調用。多次調用startService()方法儘管不會多次創建服務,但onStart() 方法會被多次調用。

 

與採用Context.bindService()方法啓動服務有關的生命週期方法

onBind()只有採用Context.bindService()方法啓動服務時纔會回調該方法。該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定,多次調用Context.bindService()方法並不會導致該方法被多次調用。

onUnbind()只有採用Context.bindService()方法啓動服務時纔會回調該方法。該方法在調用者與服務解除綁定時被調用

 

採用Context.startService()方法啓動服務的代碼如下:

public class HelloActivity extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        ......

        Button button =(Button) this.findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){

       public void onClick(View v) {

              Intent intent = new Intent(HelloActivity.this, SMSService.class);

              startService(intent);

       }});       

    }

}

 

採用Context. bindService()方法啓動服務的代碼如下:

public class HelloActivity extends Activity {

     ServiceConnection conn = new ServiceConnection() {

              public void onServiceConnected(ComponentName name, IBinder service) {

           }

           public void onServiceDisconnected(ComponentName name) {

           }

     };

    @Override public void onCreate(Bundle savedInstanceState) { 

        Button button =(Button) this.findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){

               public void onClick(View v) {

                  Intent intent = new Intent(HelloActivity.this, SMSService.class);

                  bindService(intent, conn, Context.BIND_AUTO_CREATE);

                  //unbindService(conn);//解除綁定

          }});       

    }

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章