很全面的Android面試題

這些有些來源於網站、有些來源於本身的思考。可能有些問題網上有、可能有些問題對應的答案也有,有可能有些問題講的不對,能指正的但願你們不吝指教。java

 

Activityandroid

什麼是Activity面試

四大組件之一,一個和用戶交的互界面就是一個activity,是全部 View 的容器算法

 

Activity 生命週期sql

生命週期描述的是一個類 從建立(new出來)到死亡(垃圾回收)的過程當中會執行的方法.數據庫

在這個過程當中會針對不一樣的生命階段會調用不一樣的方法緩存

Activity從建立到銷燬有多種狀態,從一種狀態到另外一種狀態時會激發相應的回調方法,這些回調方法包括:安全

  • oncreate:Activity對象建立完畢,但此時不可見
  • onstart:Activity在屏幕可見,可是此時沒有焦點
  • onResume:Activity在屏幕可見,而且得到焦點
  • onPause:Activity此時在屏幕依然可見,可是已經沒有焦點
  • onStop:Activity已經不可見了,但此時Activity的對象還在內存中
  • onDestroy:Activity對象被銷燬

其實這些方法都是兩兩對應的,onCreate建立與onDestroy銷燬;onStart可見與onStop不可見;onResume可編輯(即焦點)與onPause;服務器

還有一個onRestart方法了,在Activity被onStop後,可是沒有被onDestroy,在再次啓動此Activity時就調用onRestart(而再也不調用onCreate)方法;若是被onDestroy了,則是調用onCreate方法。微信

  

兩個Activity之間跳轉時必然會執行的是哪幾個方法。

通常狀況好比說有兩個activity,分別叫A,B ,當在A裏面激活B組件的時候, A 會調用 onPause()方法,而後B 調用onCreate() ,onStart(), OnResume() ,這個時候B覆蓋了窗體, A會調用onStop()方法.  若是B呢 是個透明的,或者是對話框的樣式, 就不會調用onStop()方法。

所以,咱們在兩個activities中傳遞數據,或者共享資源時(如數據庫鏈接),須要在前一個activity的onPause()方法而不是onStop()方法中進行

 

橫豎屏切換時候Activity的生命週期。

這個生命週期跟清單文件裏的配置有關係

一、不設置Activity的android:configChanges時,切屏會從新調用各個生命週期,默認首先銷燬當前activity,而後從新加載

二、設置Activity的android:configChanges="orientation|keyboardHidden|screenSize"時,切屏不會從新調用各個生命週期,只會執行onConfigurationChanged方法,遊戲開發中, 屏幕的朝向都是寫死的

 

如何將一個Activity設置成窗口的樣式。

能夠自定義一個activity的樣式

android:theme="@android:style/Theme.Dialog"

 

你後臺的Activity被系統 回收怎麼辦?若是後臺的Activity因爲某緣由被系統回收了,如何在被系統回收以前保存當前狀態?


 

 

 

 

 

 

除了在棧頂的activity,其餘的activity都有可能在內存不足的時候被系統回收,一個activity越處於棧底,被回收的可能性越大.若是有多個後臺進程,在選擇殺死的目標時,採用最近最少使用算法(LRU)。

Activity中提供了一個 onSaveInstanceState()回調方法,這個方法會保證必定在活動被回收以前調用, 能夠經過這個方法來解決活動被回收時臨時數據得不到保存的問題。onSaveInstanceState()方法會攜帶一個 Bundle類型的參數,Bundle提供了一系列的方法用於保存數據,好比可使用 putString()方法保存字符串,使用 putInt()方法保存整型數據。每一個保存方法須要傳入兩個參數,第一個參數是鍵,用於後面從 Bundle中取值,第二個參數是真正要保存的內容。在 MainActivity中添加以下代碼就能夠將臨時數據進行保存:

protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    String tempData = "Something you just typed";
    outState.putString("data_key", tempData);
}
onCreate()方法其實也有一個Bundle類型的參數。這個參數在通常狀況下都是null,可是當活動被系統回收以前有經過 onSaveInstanceState()方法來保存數據的話,這個參就會帶有以前所保存的所有數據
protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       if (savedInstanceState != null) {
     String tempData = savedInstanceState.getString("data_key");
     }

也能夠經過onRestoreInstanceState來存儲和恢復數據,區別是不須要判斷空了,onRestoreInstanceState調用必定是有值的

 Activity的 onSaveInstanceState() 和 onRestoreInstanceState()並非生命週期方法,它們不一樣於 onCreate()、onPause()等生命週期方法,它們並不必定會被觸發。當應用遇到意外狀況(如:內存不足、用戶直接按Home鍵)由系統銷燬一個Activity,onSaveInstanceState() 會被調用。可是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。除非該activity是被用戶主動銷燬的,一般onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。

onSaveInstanceState()被執行的場景有哪些:

系統不知道你按下HOME後要運行多少其餘的程序,天然也不知道activity A是否會被銷燬,所以系統都會調用onSaveInstanceState(),讓用戶有機會保存某些非永久性的數據。如下幾種狀況的分析都遵循該原則

  1. 當用戶按下HOME鍵時
  2. 長按HOME鍵,選擇運行其餘的程序時
  3. 鎖屏時
  4. 從activity A中啓動一個新的activity時
  5. 屏幕方向切換時

 

如何退出Activity?

退出activity 直接調用 finish () 方法 

用戶點擊back鍵 就是退出一個activity ,退出activity 會執行 onDestroy()方法 。

一、拋異常強制退出:

該方法經過拋異常,使程序Force Close。不推薦使用

驗證能夠,可是,須要解決的問題是,如何使程序結束掉,而不彈出Force Close的窗口。

安全結束進程  android.os.Process.killProcess(android.os.Process.myPid());

二、記錄打開的Activity:

每打開一個Activity,就用集合記錄下來。在須要退出時,關閉每個Activity便可。

能夠寫在Application裏,直接getApplication.list.add,在須要退出時遍歷集合裏的Activity,finish掉

也能夠定義一個baseactivity裏面進行操做,記得通常不用的話最後都須要把list=null

三、發送特定廣播:

//在baseactivity裏註冊廣播

registerReceiver(receiver, filter)

//想退出的時候就在onRecriver方法裏finish()。

四、能夠經過 intent的flag 來實現.. intent.setFlag(FLAG_ACTIVITY_CLEAR_TOP)激活一個新的activity,而後在新的activity的oncreate方法裏面就能夠finish掉.

講一講你對activity的理解 

把上面的幾點用本身的心得寫出來

 

兩個Activity之間怎麼傳遞數據?

 

  • 基本數據類型能夠經過Intent 傳遞數據  

    //把數據封裝至intent對象中

    //把數據封裝至bundle對象中
    Bundle bundle = new Bundle();
    bundle.putString("malename", "李志");
    //把bundle對象封裝至intent對象中
    intent.putExtras(bundle);

    startActivity(intent); 

  • 傳遞對象
若是要傳遞對象,須要把對象類序列化,而後intent.putExtra("mp3Info", mp3Info)
在另外一個activity,或服務、廣播中取出: Mp3Info mp3Info =(Mp3Info)intent.getSerializableExtra("mp3Info");
實現Parcelable接口的能夠用intent直接傳 ,和Serializable區別就是Parcelable是直接在內存中讀寫,要比序列化要快,
Serializabl會使用反射,序列化和反序列化過程須要大量 I/O 操做,可是要注意Parcelable傳遞對象的大小。

 

 

怎麼讓在啓動一個Activity是就啓動一個service?

在activity的onCreate()方法裏面 startService();

 

如何返回數據

基本流程:

  • 使用 startActivityForResult(Intent intent, int requestCode) 方法打開 Activity;
  • 新 Activity 中調用 setResult(int resultCode, Intent data) 設置返回數據以後,關閉 Activity 就會調用onActivityResult 方法;
  • 在原來的activity裏重寫 onActivityResult(int requestCode, int resultCode, Intent data) 方法;
  • 注意:新的 Activity 的啓動模式不能設置成 singleTask(若是已建立,會使用之前建立的)與 singleInstance(單

獨的任務棧) ,不能被摧毀(執行不到 finish 方法) ,父 Activity 中的 onActivityResult 方法將不會執行;

 

請描述一下Intent 和 Intent Filter。

Android 中經過 Intent 對象來表示一條消息,一個 Intent 對象不只包含有這個消息的目的地,還能夠包含消息的內容,這比如一封 Email,其中不只應該包含收件地址,還能夠包含具體的內容。對於一個 Intent 對象,消息「目的地」是必須的,而內容則是可選項。

經過Intent 能夠實現各類系統組件的調用與激活.

Intent filter:是傳遞的信息,這些信息不是必須的,有:

Action: 動做 view

Data: 數據uri uri

Category : 而外的附加信息

 

隱式跳轉
  • 隱式意圖跳轉至指定Activity

     

      <intent-filter >
          <action android:name="com.itheima.second"/>
          <data android:scheme="asd" android:mimeType="aa/bb"/>
          <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
    
    Intent intent = new Intent("com.example.activitytest.ACTION_START");
category 是默認的,不須要寫, 每一個 Intent中只能指定一個 action,但卻能指定多個 category
intent.addCategory("com.example.activitytest.MY_CATEGORY");
能夠調用 Intent中的 addCategory()方法來添加一個 category
intent-filter節點及其子節點均可以同時定義多個,隱式啓動時只需與任意一個匹配便可
// 電話
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL); // 設置動做
intent.setData(Uri.parse("tel://123456")); // 設置數據
// 網頁
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://192.168.1.45:8080/androidWeb"));
// 音頻/視頻,設置 type
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/daqin.mp3"), "audio/*"); // 設置數據和數據類型,將啓動音頻播放器(vedio)
 
 

PendingIntent和Intent區別

它們均可以去指明某一個「意圖」,均可以用於啓動活動、啓動服務以及發送廣播等。不一樣的是,Intent更加傾向於去當即執行某個動做,而 PendingIntent更加傾向於在某個合適的時機去執行某個動做。因此,也能夠把 PendingIntent簡單地理解爲延遲執行的 Intent。

PendingIntent的用法一樣很簡單,它主要提供了幾個靜態方法用於獲取 PendingIntent的實例,能夠根據需求來選擇是使用 getActivity()方法、getBroadcast()方法、仍是 getService()方法。

每8小時開啓廣播

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour = 8 * 60 * 60 * 1000; // 這是8小時的毫秒數
long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
Intent i = new Intent(this, AutoUpdateReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);

  

Intent傳遞數據和Bundle傳遞數據的區別

Intent傳遞數據和Bundle傳遞數據是一回事,

Intent傳遞時內部仍是調用了Bundle。

如下爲源碼:

public Intent putExtra(String name, boolean value) {
   if (mExtras == null) {
      mExtras = new Bundle();
   }
   mExtras.putBoolean(name, value);
   return this;
}

  

啓動一個Activity有哪幾種方法

startActivity

startActivityforresult

launcher的activity

widget

 


同一個程序,但不一樣的Activity是否能夠放在不一樣的Task任務棧中?

啓動模式裏有個Singleinstance,能夠運行在另外的單獨的任務棧裏面。用這個模式啓動的activity,在內存中只有一份,這樣就不會重複的開啓。

也能夠在激活一個新的activity時候, 給intent設置flag,Intent的flag添加FLAG_ACTIVITY_NEW_TASK,這個被激活的activity就會在新的task棧裏面

 

Android中Task任務棧的分配。

1)任務棧的概念

問:一個手機裏面有多少個任務棧?

答:通常狀況下,有多少個應用正在運行,就對應開啓多少個任務棧;每開啓一個應用程序就會建立一個與之對應的任務棧;

棧:後進先出,最早進棧,就會最後出棧。Activity的啓動模式就是修改任務棧的排列狀況

2)任務棧的做用:

它是存放 Activity 的引用的,Activity不一樣的啓動模式,對應不一樣的任務棧的存放;

可經過 getTaskId()來獲取任務棧的 ID,若是前面的任務棧已經清空,新開的任務棧 ID+1,是自動增加的;

 首先來看下Task的定義,Google是這樣定義Task的:Task其實是一個Activity棧,一般用戶感覺的一個Application就是一個Task。從這個定義來看,Task跟Service或者其餘Components是沒有任何聯繫的,它只是針對Activity而言的。

 

 Activity的啓動模式

standard 標準啓動模式(本身啓動本身會按三次才能退出)
singleTop 單一頂部模式
    • 若是任務棧的棧頂存在這個要開啓的activity,不會從新的建立activity,而是複用已經存在的activity。若是棧頂沒有或者不在棧頂,會從新建立
    • 會調用 onNewInstance(),複用已經存在的實例
    • 應用場景:singleTop適合接收通知啓動的內容顯示頁面。例如,某個新聞客戶端的新聞內容頁面,若是收到10個新聞推送,每次都打開一個新聞內容頁面是很耗內存的。
singeTask 單一任務棧,在當前任務棧裏面只能有一個實例存在
  • 當開啓activity的時候,就去檢查在任務棧裏面是否有實例已經存在,若是有實例存在就複用這個已經存在的activity,而且把這個activity上面的全部的別的activity都清空,複用這個已經存在的activity。保證整個任務棧裏面只有一個實例存在
  • 會調用 onNewInstance(),複用已經存在的實例
  • 應用場景:
singleTask適合做爲程序入口點,例如應用中的主頁(Home頁)。假設用戶在主頁跳轉到其餘頁面,運行屢次操做後想返回到主頁,假設不使用SingleTask模式,在點擊返回的過程當中會屢次看到主頁,這明顯就是設計不合理了。

singleInstance:activity會運行在本身的任務棧裏面,而且這個任務棧裏面只有一個實例存在
    • 若是你要保證一個activity在整個手機操做系統裏面只有一個實例存在,使用singleInstance
    • 應用場景: 電話撥打界面
singleInstance適合須要與程序分離開的頁面。例如咱們有個需求,須要打開別的應用,這個時候若是不設置singleInstance的話,這個新打開的應用在咱們程序的任務棧裏,用戶想要按任務鍵切換的話無法切換。

 

 

 

Android下的進程

進程是被系統建立的,當內存不足的時候,又會被系統回收

內存管理:Android 系統在運行多個進程時,若是系統資源不足,會強制結束一些進程,優先選擇哪一個進程來結束是有優先級的。

會按照如下順序殺死(進程級別):

①、空: 進程中沒有任何組件(無組件啓動,作進程緩存使用,恢復速度快),任務棧清空,意味着程序退出了,但進程留着,這個就是空進程,容易被系統回收;

②、後臺:進程中只有中止狀態(onStop)的 Activity;

③、服務:進程中有正在運行的服務;

④、可見:進程中有一個暫停狀態(onPause)的 Activity;

⑤、前臺:進程中正在運行一個 Activity;

Activity 在退出的時候進程不會銷燬, 會保留一個空進程方便之後啓動. 但在內存不足時進程會被銷燬;

Activity 中不要在 Activity 作耗時的操做, 由於 Activity 切換到後臺以後(Activity 中止了), 內存不足時, 也容易被銷毀;

 

 

 Service

什麼是Service以及描述下它的生命週期。Service有哪些啓動方法,有什麼區別,怎樣停用Service?

在Service的生命週期中,被回調的方法比Activity少一些,只有onCreate, onStartCommand, onDestroy,onBind和onUnbind。

一般有兩種方式啓動一個Service,他們對Service生命週期的影響是不同的。

1 經過startService

    Service會經歷 onCreate 到onStartCommand,而後處於運行狀態,stopService的時候調用onDestroy方法。

   若是是調用者本身直接退出而沒有調用stopService的話,Service會一直在後臺運行。

2 經過bindService   

    Service會運行onCreate,而後是調用onBind, 這個時候調用者和Service綁定在一塊兒。調用者退出了,Srevice就會調用onUnbind->onDestroyed方法。所謂綁定在一塊兒就共存亡了。調用者也能夠經過調用unbindService方法來中止服務,這時候Srevice就會調用onUnbind->onDestroyed方法。

 

1.一旦在項目的任何位置調用了Context的startService()方法,相應的服務就會啓動起來,並回調onStartCommand()方法。若是這個服務以前尚未建立過,onCreate()方法會先於onStartCommand()方法執行。
2.服務啓動了以後會一直保持運行狀態,直到 stopService()或stopSelf()方法被調用。注意雖然每調用一次startService()方法,onStartCommand()就會執行一次,但實際上每一個服務都只會存在一個實例。因此無論調用了多少次startService()方法,只需調用一次stopService()或stopSelf()方法,服務就會中止下來了。

3.當調用了startService()方法後,又去調用 stopService()方法,這時服務中的 onDestroy()方法就會執行,表示服務已經銷燬了。相似地,當調用了 bindService()方法後,又去調用unbindService()方法,onDestroy()方法也會執行,這兩種狀況都很好理解。可是須要注意,咱們是徹底有可能對一個服務既調用了startService()方法,又調用了bindService()方法的,這種狀況下該如何才能讓服務銷燬掉呢?根據Android系統的機制,一個服務只要被啓動或者被綁定了以後,就會一直處於運行狀態,必需要讓以上兩種條件同時不知足,服務才能被銷燬。因此,這種狀況下要同時調用stopService()和unbindService()方法,onDestroy()方法纔會執行這樣就把服務的生命週期完整地走了一遍。

start –> bind -> unbind -> stop 常用服務長期後臺運行,又能夠調用服務中的方法

 

service如何殺不死?

1.onStartCommand方法,返回START_STICKY(粘性)當service因內存不足被kill,當內存又有的時候,service又被從新建立

2.設置優先級,在服務裏的ondestory裏發送廣播 在廣播裏再次開啓這個服務,雙進程守護

 

service是否在main thread中執行, service裏面是否能執行耗時的操做?

默認狀況,若是沒有顯示的指定service所運行的進程, Service和Activity是運行在當前app所在進程的main thread(UI主線程)裏面

service裏面不能執行耗時的操做(網絡請求,拷貝數據庫,大文件 ),須要在子線程中執行 new Thread(){}.start();

 

service裏面能夠彈土司嗎

service裏面彈toast須要添加到主線程裏執行
  @Override  
    public void onCreate(){  
        handler = new Handler(Looper.getMainLooper());                          
        System.out.println("service started");  
       handler.post(new Runnable() {    
             @Override    
             public void run() {    
                Toast.makeText(getApplicationContext(), "Test",Toast.LENGTH_SHORT).show();
                });
     }

 

Activity怎麼和service綁定,怎麼在activity中啓動本身對應的service?

startService() 一旦被建立 調用着無關,無法使用service裏面的方法

bindService () 把service 與調用者綁定 ,若是調用者被銷燬, service會銷燬,可使用service 裏面的方法

 

 Service與Activity怎麼實現通訊

方法一:

  1. 添加一個繼承Binder的內部類,並添加相應的邏輯方法
  2. 重寫Service的onBind方法,返回咱們剛剛定義的那個內部類實例
  3. Activity中建立一個ServiceConnection的匿名內部類,而且重寫裏面的onServiceConnected方法和onServiceDisconnected方法,這兩個方法分別會在活動與服務成功綁定以及解除綁定的時候調用,在onServiceConnected方法中,咱們能夠獲得一個剛纔那個service的binder對象,經過對這個binder對象進行向下轉型,獲得咱們那個自定義的Binder實例,有了這個實例,作能夠調用這個實例裏面的具體方法進行須要的操做了

方法二
經過BroadCast(廣播)的形式
當咱們的進度發生變化的時候咱們發送一條廣播,而後在Activity的註冊廣播接收器,接收到廣播以後更新視圖

 

什麼是IntentService?有何優勢?

普通的service ,默認運行在ui main 主線程,Sdk給咱們提供的方便的,帶有異步處理的service類

OnHandleIntent() 處理耗時的操做,不須要開啓子線程,這個方法已經在子線程中運行了

Intentservice若未執行完成上一次的任務,將不會新開一個線程,是等待以前的任務完成後,再執行新的任務,等任務完成後再次調用stopService()

 

startForeground(idnotification)

擁有service的進程具備較高的優先級。當內存不足時,擁有service的進程具備較高的優先級。

1. 若是service正在調用onCreate,  onStartCommand或者onDestory方法,那麼用於當前service的進程至關於前臺進程以免被killed。

2. 若是當前service已經被啓動(start),擁有它的進程則比那些用戶可見的進程優先級低一些,可是比那些不可見的進程更重要,這就意味着service通常不會被killed.

3. 若是客戶端已經鏈接到service (bindService),那麼擁有Service的進程則擁有最高的優先級,能夠認爲service是可見的。

4. 若是service可使用startForeground(int, Notification)方法來將service設置爲前臺狀態,那麼系統就認爲是對用戶可見的,並不會在內存不足時killed。

 

何時使用Service?

若是有其餘的應用組件做爲Service,Activity等運行在相同的進程中,那麼將會增長該進程的重要性。

1.Service的特色可讓他在後臺一直運行,能夠在service裏面建立線程去完成耗時的操做.

2.Broadcast receiver捕獲到一個事件以後,能夠起一個service來完成一個耗時的操做.

 

 

廣播

請描述一下Broadcast Receiver。

Android中:系統在運行過程當中,會產生會多事件,那麼某些事件產生時,好比:電量改變、收發短信、撥打電話、屏幕解鎖、開機,系統會發送廣播,只要應用程序接收到這條廣播,就知道系統發生了相應的事件,從而執行相應的代碼。使用廣播接收者,就能夠收聽廣播

廣播分兩種:有序廣播、無序廣播

無序廣播:無序廣播不可中斷,不能互相傳遞數據;

有序廣播:一個接一個的傳遞,廣播可中斷,經過調用 abortBroadcast()方法;接收者之間能夠傳遞數據(intent);

無序廣播(標準廣播)

  • 全部與廣播中的action匹配的廣播接收者均可以收到這條廣播,而且是沒有前後順序,視爲同時收到

有序廣播

  • 全部與廣播中的action匹配的廣播接收者均可以收到這條廣播,可是是有前後順序的,按照廣播接收者的優先級排序
    • 優先級的定義:-1000~1000
    •  <intent-filter android:priority="100" >
      <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
      </intent-filter>
    • 最終接收者:全部廣播接收者都接收到廣播以後,它才接收,而且必定會接收
    • abortBroadCast:阻止其餘接收者接收這條廣播,相似攔截,只有有序廣播能夠被攔截
 

如何註冊廣播

廣播的方式通常有兩種,在代碼中註冊和在 AndroidManifest.xml中註冊,其中前者也被稱爲動態註冊,後者也被稱爲靜態註冊。
動態註冊 須要使用廣播接收者時,執行註冊的代碼,不須要時,執行解除註冊的代碼
  • 安卓中有一些廣播接收者,必須使用代碼註冊,清單文件註冊是無效的
  1. 屏幕鎖屏和解鎖
  2. 電量改變
public class MainActivity extends Activity {
    private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
           intentFilter = new IntentFilter();
           intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
           networkChangeReceiver = new NetworkChangeReceiver();
           registerReceiver(networkChangeReceiver, intentFilter);
    }
    @Override
    protected void onDestroy() {
           super.onDestroy();
           unregisterReceiver(networkChangeReceiver);
    }
    class NetworkChangeReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                 Toast.makeText(context, "network changes",Toast.LENGTH_SHORT).show();
            }
    }
}
靜態註冊:
可使用清單文件註冊
  • 廣播一旦發出,系統就會去全部清單文件中尋找,哪一個廣播接收者的action和廣播的action是匹配的,若是找到了,就把該廣播接收者的進程啓動起來

四大組件其中比較特殊的是廣播接收者,能夠不在清單文件中配置,能夠經過代碼進行註冊。其餘組件所有在清單文件中註冊

 

避免使用隱式 Intent 廣播(靜態、動態註冊)敏感信息,信息可能被其餘註冊了對應BroadcastReceiver 的 App 接收 
若是廣播僅限於應用內,則可使用 LocalBroadcastManager#sendBroadcast()實現,避免敏感信息外泄和 Intent 攔截的風險。 
Intent intent = new Intent("my-sensitive-event");
intent.putExtra("event", "this is a test event");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 

  

 

廣播的生命週期

a. 廣播接收者的生命週期很是短暫的,在接收到廣播的時候建立,onReceive()方法結束以後銷燬;

b. 廣播接收者中不要作一些耗時的工做,不然會彈出 Application No Response錯誤對話框;

c. 最好也不要在廣播接收者中建立子線程作耗時的工做,由於廣播接收者被銷燬後進程就成爲了空進程,很容易被系統殺掉;

d. 耗時的較長的工做最好放在服務中完成;


 

 

內容提供者

請介紹下ContentProvider是如何實現數據共享的。

是四大組件之一內容提供者的做用:把私有數據暴露給其餘應用,一般,是把私有數據庫的數據暴露給其餘應用

應用的數據庫是不容許其餘應用訪問的,內容提供者的做用就是讓別的應用訪問到你的數據庫。

在清單文件中定義內容提供者的標籤,注意必需要有authorities屬性,這是內容提供者的主機名,功能相似地址

  <provider android:name="com.itheima.contentprovider.PersonProvider"
      android:authorities="com.itheima.person"
      android:exported="true"
   ></provider>

把本身的數據經過uri的形式共享出去,android 系統下不一樣程序,數據默認是不能共享訪問 

須要去實現一個類去繼承ContentProvider 

 

爲何要用ContentProvider?它和sql的實現上有什麼差異?

屏蔽數據存儲的細節,對用戶透明,用戶只須要關心操做數據的uri就能夠了

不一樣app之間共享,操做數據

Sql也有增刪改查的方法.

可是contentprovider 還能夠去增刪改查本地文件. xml文件的讀取,更改,網絡數據讀取更改

 

 

請介紹下Android的數據存儲方式

1.文件儲存,在內部文件和SD卡

getCacheDir(),在data/data/包名/cache

getFilesDir(),在data/data/包名/files

SD卡:首先通File file = new File(Environment.getExternalStorageDirectory(), "info.txt"),而後經過io存儲

2.SharedPreference 

3.SQLite數據庫
當應用程序須要處理的數據量比較大時,爲了更加合理地存儲、管理、查詢數據,每每使用關係數據庫來存儲數據。Android系統的不少用戶數據,如聯繫人信息,通話記錄,短信息等,都是存儲在SQLite數據庫當中的,因此利用操做SQLite數據庫的API能夠一樣方便的訪問和修改這些數據。

4.ContentProvider:
主要用於在不一樣的應用程序之間實現數據共享的功能,不一樣於sharepreference和文件存儲中的兩種全局可讀寫操做模式,內容提供其能夠選擇只對哪一部分數據進行共享,從而保證咱們程序中的隱私數據不會有泄漏的風險

 

 

Fragment

簡單說說Fragment

用途:在一個Activity裏切換界面,切換界面時只切換Fragment裏面的內容

生命週期方法跟Activity一致,能夠理解把其爲就是一個Activity,與Activity同存亡,Activity的XX方法調用,Fragment的XX方法就調用

 

他們是怎麼進行傳遞數據的?

活動傳遞給Fragment:爲了方便碎片和活動之間進行通訊, FragmentManager提供了一個相似於findViewById()的方法,專門用於從佈局文件中獲取碎片的實例,前提是本身在佈局文件中定義fragment這個標籤,代碼以下所示:

RightFragment rightFragment = (RightFragment) getFragmentManager()
.findFragmentById(R.id.right_fragment);
 

調用 FragmentManager的 findFragmentById()方法,能夠在活動中獲得相應碎片的實例,而後就能輕鬆地調用碎片裏的方法了。還有findViewByTag,在replace 的時候設置tag

或者在fragment裏聲明接口,而後activity得到fragment對象調用接口裏的方法

 

fragment數據傳遞給活動,直接getActivity就能夠調用活動裏的方法了

activity給fragment傳遞數據通常不經過fragment的構造方法來傳遞,會經過setArguments來傳遞,由於當橫豎屏會調用fragment的空參構造函數,數據丟失。

 

fragmentfragment數據傳遞

首先在一個fragment能夠獲得與它相關聯的活動,而後再經過這個活動去獲取另一個fragment的實例,這樣也就實現了不一樣fragment之間的通訊功能

 

FragmentManager , add 和 replace 有什麼區別?

  • 使用 FragmentTransaction 的時候,它提供了這樣兩個方法,一個 add , 一個 replace ,add 和 replace 影響的只是界面,而控制回退的,是事務。
  • add 是把一個fragment添加到一個容器 container 裏。replace 是先remove掉相同id的全部fragment,而後在add當前的這個fragment。
  • 在大部分狀況下,這兩個的表現基本相同。由於,通常,我們會使用一個FrameLayout來當容器,而每一個Fragment被add 或者 replace 到這個FrameLayout的時候,都是顯示在最上層的。因此你看到的界面都是同樣的。可是, 使用add的狀況下,這個FrameLayout其實有2層,多層確定要比一層的來得浪費,因此仍是推薦使用replace。 固然有時候仍是須要使用add的。好比要實現輪播圖的效果,每一個輪播圖都是一個獨立的Fragment,而他的容器FrameLayout須要add多個Fragment,這樣他就能夠根據提供的邏輯進行輪播了。而至於返回鍵的時候,這個跟事務有關,跟使用add仍是replace沒有任何關係。
  • replace()方法會將被替換掉的那個Fragment完全地移除掉,所以最好的解決方案就是使用hide()和show()方法來隱藏和顯示Fragment,這就不會讓Fragment的生命週期重走一遍了

 

Fragment和view的區別

Fragment能夠有效的對 view進行管理(增刪和替換)並且結構更加清晰,有模塊化的實現思想。

用view 不少邏輯代碼可能都須要寫在Activity裏,若是view不少, 耦合度會很高。用Fragment則能夠各自管理,起了解耦的做用。

通常軟件簡單的話直接view,複雜的用Fragment

viewpager是一個滑動切換的控件Fragment是一個輕量級的Activity,這個Fragment能夠放到這個Viewpager裏面去運行。

例如QQ或微信那樣,能夠來回切換不一樣的選項卡,即切換了不一樣的Fragment一般Viewpager 會放fargment或者view

 

Fragment和Activity的區別

由於如今的手機屏幕都比較大了,Activity會把內容拉的很長,用Fragment的話能夠左側是列表,右側是內容。在一個Activity裏切換界面,切換界面時只切換Fragment裏面的內容。Fragment一般用來做爲一個activity界面的一部分。

 

view

請介紹下Android中經常使用的五種佈局。

FrameLayout(幀佈局),LinearLayout (線性佈局),AbsoluteLayout(絕對佈局),RelativeLayout(相對佈局),TableLayout(表格佈局)

  • FrameLayout:從屏幕的左上角開始佈局,疊加顯示, 實際應用 播放器的暫停按鈕. 
  • LinearLayout:線性佈局,他首先是一個一個從上往下羅列在屏幕上。每個LinearLayout裏面又可分爲垂直佈局、水平佈局。當垂直佈局時,每一行就只有一個元素,多個元素依次垂直往下;水平佈局時,只有一行,每個元素依次向右排列。
  • AbsoluteLayout:用X,Y座標來指定元素的位置android:layout_x="20px" ,android:layout_y="12px" ,指定平板機型的遊戲開發、機頂盒開發中常常用到絕對佈局
  • RelativeLayout:在相對的佈局中主要就進行避免覆蓋的問題,就是組件1可能會覆蓋在組件2上(屏幕適配),在相對的佈局中主要就進行避免覆蓋的問題,就是組件1可能會覆蓋在組件2上
  • TableLayout:有幾行,就有幾個<TableRow/>,有幾列,那麼在<TableRow>中就有幾個<TestView>,TableRow的子節點的寬和高是包裹內容,不須要指定寬高
  

TextView 、ImageView ,Button,ImageButton他們之間的聯繫和區別

ImageView 控件負責顯示圖片,其圖片來源既能夠是資源文件的id,也能夠是Drawable對象或 Bitmap 對象,還能夠是 內容提供者(Content Provider)的Uri.

ImageButton 控件 繼承自 ImageView。與Button相同之處:都用於響應按鈕的點擊事件

不一樣之處:ImageButton只能顯示圖片;Button用於顯示文字

 

屏幕適配

  • 開發時選取主流屏幕 1280*720,用相對佈局和線性佈局
  • 用dp sp不用px,dp單位動態匹配
  • 開發後期在不一樣的分辨率上測試,沒有太大問題能夠上線
  • 權重適配:weight 只有線性佈局有
  • 代碼適配:getWindowManager().getDefaultDisplay().getWidth();得到屏幕的寬高
  • 若是屏幕放不下了,可使用 ScrollView(能夠上下拖動)
  • 佈局適配:layout-800x180 針對某一種屏幕 工做量大
  • 尺寸適配:dp=px/設備密度=getResource().getDisplayMetrice().dsnsity;
  • 根據不一樣分辨率的屏幕創建不一樣的valuse,好比valuse-1280x720,values裏的dimens裏算出dp,最後引用系統會自動匹配。
(約等於)320*240(0.5) 480*320(1) 480*800(1.5) 1280*720(2)就不用佈局適配了
  • 在進行開發的時候,咱們須要把合適大小的圖片放在合適的文件夾裏面。大分辨率圖片(單維度超過 1000)大分辨率圖片建議統一放在 xxhdpi 目錄下管理,不然將致使佔用內存成倍數增長。
說明: 爲了支持多種屏幕尺寸和密度,Android 爲多種屏幕提供不一樣的資源目錄進行適配。爲不一樣屏幕密度提供不一樣的位圖可繪製對象,可用於密度特定資源的配置限定符(在下面詳述) 包括 ldpi(低)、 mdpi(中)、 hdpi(高)、 xhdpi(高)、 xxhdpi (超超高)和 xxxhdpi(超超超高)。例如,高密度屏幕的位圖應使用 drawable-hdpi。根據當前的設備屏幕尺寸和密度,將會尋找最匹配的資源,若是將高分辨率圖片放入低密度目錄,將會形成低端機加載過大圖片資源,又可能形成 OOM,同時也是資源浪費,沒有必要在低端機使用大。

 

RelativeLayout和FrameLayout的區別

FrameLayout主要是在多層之間的佈局,RelativeLayout則是在同層之間不一樣位置之間的佈局,效果上沒有什麼大的區別,均可以實現,只是看哪一種實現更容易。好比咱們收到信息了,咱們能夠在信息圖標上增長FrameLayout 用於顯示氣泡。

 

Padding和Margin有什麼區別?

Padding 是控件內容的距離margin是控件和控件間的距離

 

Listview如何顯示不一樣條目?

第一種:在getview方法里根據position 進行判斷,好比,position等於0是,顯示標題,不然顯示數據,固然相應的setOnItemClickListener也要去判斷

第二種:根據listview裏的getItemViewType,getViewTypeCount方法顯示不一樣條目

    /** 根據位置 判斷當前條目是什麼類型 */
    @Override
    public int getItemViewType(int position) {  //20     
        if (position == datas.size()) { // 當前是最後一個條目
            return MORE_ITEM;
        }
        return getInnerItemViewType(position); // 若是不是最後一個條目 返回默認類型
    }
    private int getInnerItemViewType(int position) {
        return DEFAULT_ITEM;
    }
    /** 當前ListView 有幾種不一樣的條目類型 */
    @Override
    public int getViewTypeCount() {
        return super.getViewTypeCount() + 1; // 2 有兩種不一樣的類型
    }

  

ScrowView 使用的注意

在不一樣的屏幕上顯示內容不一樣的狀況,其實這個問題咱們每每是用滾動視圖來解決的,也就是 ScrowView,

須要注意的是 ScrowView 中使用 layout_weight 是無效的,既然使用 ScrowView 了,就把它裏面的控件的大小都設成固定的吧。

 

Android UI中的View如何刷新

在主線程中 拿到view調用Invalide()方法,在子線程裏面能夠經過postInvalide()方法;

invalidate();//主線程,刷新當前視圖 致使 執行onDraw執行

postInvalidate();//子線程

 

什麼是ANR(異步加載) 如何避免它?

android在主線程是不能加載網絡數據或圖片、數據庫查詢、複雜業務邏輯處理以及費時任務操做,由於Android的UI操做並非線程安全的,而且全部涉及UI的操做必須在UI線程中完成。Android應用在5s內無響應的話會致使ANR(Application Not Response),這就要求開發者必須遵循兩條法則:一、不能阻塞UI線程,二、確保只在UI線程中訪問Android UI工具包。

Activity 5秒 broadcast10秒,服務20秒,耗時的操做在主thread裏面完成

解決辦法:Thread + Handler + Message ,Thread + Handler + post,AsyncTask,intentservice

runOnUiThread(Runnable)在子線程中直接使用該方法,能夠更新UI

 

實現側邊欄、和指示器效果、頁面滑動有幾種方式

側邊欄:自定義、slidingmenu、DrawerLayout 、SlidingDrawer

指示器效果:自定義、viewpager裏面的PagerTabStrip、ActionBar Tab標籤、viewpagerindicate、FragmentTabHost、TabActivity、radiobutton

頁面滑動:自定義、viewpager、手勢識別器,其實就是onTouchEvent提供的簡單工具類,onTouchEvent將觸摸事件委託給了手勢識別器

 

 

其餘

Gradle中buildToolsVersion和TargetSdkVersion的區別是什麼

compileSdkVersion, minSdkVersion 和 targetSdkVersion 的做用:他們分別控制可使用哪些 API ,要求的 API 級別是什麼,以及應用的兼容模式。TargetSdkVersion 設爲23那麼是按6.0設置的(運行時權限),小於23是按6.0之前的方式(安裝時默認得到權限,且用戶沒法在安裝App以後取消權限)

 

進程間怎麼通訊

binder是安卓中的一個類,它實現了IBinder接口,是安卓中跨進程通訊的方式。當綁定服務的時候會返回一個binder對象,而後經過他進行多進程間的通訊。

其實進程間通訊就是爲了實現數據共享。一個程序不一樣組件在不一樣進程也叫多進程,和倆個應用沒有本質區別。使用process屬性能夠實現多進程,可是會帶來不少麻煩,主要緣由是共享數據會失敗,弊端有:靜態和單利失效,同步失效,sharedprefer可靠性減低等問題

Intent,Binder(AIDL),sharedpre、Messenger

  • 使用intent的附加信息extras來傳遞,經過bundle,傳遞的是bundle支持的類型,好比基本數據類型、實現pracellable或serializeable的對象
  • 使用文件共享,序列化或是sharedpre,不過不適用於讀寫併發的操做
  • 經過message進行傳遞,在遠程服務裏建立message對像,在onbind裏返回(message.getbinder)。在客戶端綁定服務,拿着message對象發消息(能夠用bundle)。在遠程服務的handlermessage方法就會收到。他是一個個處理的,若是大量併發請求用aidl,mrssage底層就是aidl
  • AIDL
  • socket能夠實現倆個終端通訊,也能夠在一個設備的倆個進程通訊。須要在服務裏建立服務端
  • ContentProvider(進程間數據共享)和message同樣,底層也是binder,除了oncreate方法其餘方法(crud)都是運行在bindler線程裏。因此在oncerate裏不能作耗時操做。在其餘應用訪問經過uri(主機名),例如gercontentResolver.query(uri,null,null....)
  • 有以上6種

使用多進程顯而易見的好處就是分擔主進程的內存壓力。咱們的應用越作越大,內存愈來愈多,將一些獨立的組件放到不一樣的進程,它就不佔用主進程的內存空間了。固然還有其餘好處,有心人會發現Android後臺進程裏有不少應用是多個進程的,由於它們要常駐後臺,特別是即時通信或者社交應用,不過如今多進程已經被用爛了。典型用法是在啓動一個不可見的輕量級私有進程,在後臺收發消息,或者作一些耗時的事情,或者開機啓動這個進程,而後作監聽等。還有就是防止主進程被殺守護進程,守護進程和主進程之間相互監視,有一方被殺就從新啓動它。

 

假設手機本地須要緩存數據,如何保證和服務器的數據統一?

  • 好比有個網絡更新的功能,activity能夠每隔半小時開啓service去訪問服務器,獲取最新的數據。

  • 在緩存文件裏面加入時間戳,根據實際狀況在必定的時間差內再次訪問網絡數據、判斷URL

在緩存的第一行寫一個上當前時間,讀的時候判斷是否是過時,根據需求看須要多久跟新

 

分頁怎麼作的?

分頁根據服務器接口參數決定每次加載多少,getviewtype,getitemview

分批處理 解決的是時間等待的問題,不能解決內存佔用的問題。

要想解決內存佔用問題,能夠採用分頁方式

 

什麼Context

Android工程環境中像Activity、Service、BroadcastReceiver等系統組件,而這些組件並非像一個普通的Java對象new一下就能建立實例的了,而是要有它們各自的上下文環境,這就是Context。能夠這樣講,Context是維持Android程序中各組件可以正常工做的一個核心功能類。

Context功能不少,能夠彈出Toast、啓動Activity、啓動Service、發送廣播、操做數據庫等等等等都須要用到Context。

Context一共有Application、Activity和Service三種類型:Context數量 = Activity數量 + Service數量 + 1 。1表明着Application的數量,由於一個應用程序中能夠有多個Activity和多個Service,可是隻能有一個Application。
Application一般做爲工具類來使用的,Application中在onCreate()方法裏去初始化各類全局的變量數據是一種比較推薦的作法,可是若是你想把初始化的時間點提早到極致,也能夠去重寫attachBaseContext()方法。不能寫在構造函數裏。

 

Android程序與Java程序的區別?

Android程序用android sdk開發,java程序用javasdk開發.

Android SDK引用了大部分的Java SDK,少數部分被Android SDK拋棄,好比說界面部分,java.awt swing package除了java.awt.font被引用外,其餘都被拋棄,在Android平臺開發中不能使用。 Android sdk 添加工具jar httpclient , pull opengl

 

Android中的動畫有哪幾類,它們的特色和區別是什麼?

三種:補間動畫、幀動畫、屬性動畫。
補間動畫是放置到res/anim/下面
幀動畫是放置到res/drawable/下面,子節點爲animation-list,在這裏定義要顯示的圖片和每張圖片的顯示時長
補間動畫
  • 若是動畫中的圖像變換比較有規律時,例如圖像的移動(TranslateAnimation)、旋轉(RotateAnimation)、縮放(ScaleAnimation)、透明度漸變(AlphaAnimation),這些圖像變化過程當中的圖像均可以根據必定的算法自動生成,咱們只須要指定動畫的第一幀和最後一幀圖像便可,這種自動生成中間圖像的動畫就是補間動畫。
  • 補間動畫,只是一個動畫效果,組件其實還在原來的位置上,xy沒有改變
幀動畫:傳統的動畫方法,經過順序的播放排列好的圖片來實現,相似電影,一張張圖片不斷的切換,造成動畫效果,要本身指定每一幀

屬性動畫:動畫的對象除了傳統的View對象,還能夠是Object對象,動畫結束後,Object對象的屬性值被實實在在的改變了

 

Android工程的目錄結構 

src:項目的java代碼

assets:資源文件夾,存放視頻或者音樂等較大的資源文件

bin:存放應用打包編譯後的文件

res:資源文件夾,在這個文件夾中的全部資源,都會有資源id,讀取時經過資源id就能夠讀取

     資源id不能出現中文

 

coverview原理:

這個參數用於將以前加載好的佈局進行緩存,以便以後能夠進行重用,在 getView()方法中進行了判斷,若是 convertView爲空,則使用

LayoutInflater去加載佈局,若是不爲空則直接對 convertView進行重用

 

android的啓動流程

當程序啓動Linux內核後,會加載各類驅動和數據結構,當有了驅動之後,開始啓動Android系統同時會加載用戶級別的第一個進程init(system\core\init.c),加載init.rc文件,會啓動一個Zygote進程,此進程是Android系統的一個母進程,用來啓動Android的其餘服務進程,而後接着在裏面啓動各類硬件服務和activity。Android系統啓動完成,打開了Luncher應用的Home界面。

 

Logcat

1. Log.v()

這個方法用於打印那些最爲瑣碎的,意義最小的日誌信息。對應級別 verbose,是Android日誌裏面級別最低的一種。

2. Log.d()

這個方法用於打印一些調試信息, 這些信息對你調試程序和分析問題應該是有幫助的。對應級別 debug,比 verbose高一級。

3. Log.i()

這個方法用於打印一些比較重要的數據,這些數據應該是你很是想看到的,能夠幫你分析用戶行爲的那種。對應級別 info,比 debug高一級。

4. Log.w()

這個方法用於打印一些警告信息,提示程序在這個地方可能會有潛在的風險,最好去修復一下這些出現警告的地方。對應級別 warn,比 info高一級。

5. Log.e()

這個方法用於打印程序中的錯誤信息,好比程序進入到了 catch語句當中。當有錯誤信息打印出來的時候,通常都表明你的程序出現嚴重問題了,必須儘快修復。對應級別 error,比 warn高一級.

 

推送

全部須要客戶端被動接收信息的功能模塊,均可以用推送實現,好比A想給B發消息,A調服務器接口,服務器只是存數據,它調推送的接口,推送去去找B。推送用的是xmpp協議, 是一種基於TCP/IP的協議, 這種協議更適合消息發送

- socket 套接字, 發送和接收網絡請求
- 長鏈接 keep-alive, 服務器基於長鏈接找到設備,發送消息
- 心跳包 , 客戶端會定時(30秒一次)向服務器發送一段極短的數據,做爲心跳包, 服務器定時收到心跳,證實客戶端或者,纔會發消息.不然將消息保存起來,等客戶端活了以後(從新鏈接),從新發送.

 

 因爲篇幅緣由,附倆篇優化和自定義控件常見的面試題,但願對你們有所幫助:

Android優化指南

Android自定義控件概念總結

相關文章
相關標籤/搜索