1. 程式人生 > >Android面試四大元件基礎知識點

Android面試四大元件基礎知識點

四大元件是什麼

目錄

一.activity

生命週期圖
這裡寫圖片描述

1.一個Activity通常就是一個獨立的視窗,Activity各種情況下的生命週期

①正常情況的生命週期
onCreate –>onStart–>onResume–>onPause–>onStop–>onDestory

②橫豎屏切換的時候
如果突然旋轉螢幕,由於系統配置發生了改變,在預設情況下,Activity就會被銷燬並重新建立
這裡寫圖片描述
在Activity中新增android:configChanges="orientation|keyboardHidden|screenSize"

屬性可以避免Activity生命週期被回撥

③Activity上彈出Dialog,彈出時然後按Home鍵時的生命週期
Activity上彈出Dialog:onCreate–>onStart–>onResume
當啟動和退出Dialog時,Activity的狀態始終未變,,因為Dialog實際上時一個View,它是屬於某一個Activity的,因此如果Dialog顯示在當前Activity之前時不會影響到Activity的生命週期的
dialog彈出時按Home鍵:onPause–>onStop

整個流程如下:
這裡寫圖片描述
④前臺切換到後臺,然後再回到前臺,Activity生命週期回撥方法。
這裡寫圖片描述


⑤兩個Activity 之間跳轉
MainActivity 和 DragActivity
這裡寫圖片描述
MainActivity 經歷的週期:onCreate–>onStart–>onResume–>onPause–>onStop–>onRestart–>onStart–>onResume
DragActivity 經歷的週期:onCreate–>onstart–>onResume–>onPause–>onStop–>onDestory

2.Activity之間的通訊方式

startActivity

Intent intent = new
Intent(this, SignInActivity.class); startActivity(intent);

startActivityForResult

Intent intent = new Intent(getContext(), PresentManageActivity.class);
intent.putExtra(PresentManageActivity.KEY_START_NUM, mStartNum);
startActivityForResult(intent, RequestCode.REQUEST_CODE_GIFT);

LocalBroadcastReceiver

3.android應用中的每個Activity都應該在AndroidManifest.xml配件檔案中宣告,否則系統將不識別也不執行該Activity

4.活動被回收,Activity狀態保存於恢復

Activity提供了onSaveInstanceState()回撥方法,這個方法可以保證在活動回收之前被呼叫,
onSaveInstanceState()方法會攜帶一個Bundle型別的引數,Bundle提供了一些方法用於儲存資料

 @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("data", "儲存資料");
    }

儲存的資料在onCreate()方法中可獲取

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(savedInstanceState!=null){
        String data = savedInstanceState.getString("data");
        }
 }

5.Activity的四種啟動模式對比

①Standard:系統預設的啟動模式,每次啟動一個activity都會建立一個新的例項,不管這個例項是否存在

②SingleTop:棧頂複用模式,如果activity已經在任務棧的棧頂了,當再次啟動同一個activity的時候,這個activity不會被重新建立,而且它的onNewIntent()方法會被呼叫
適合接受通知啟動的內容頁面,例如:某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都開啟一個新聞內容頁面是很煩人的。

③SingleTask:棧內複用模式,只要activity存在棧內,那麼多次啟動activity都不會重新建立例項,再次啟動時該例項被移到棧頂,系統會呼叫它的onNewIntent()方法
適合做程式的入口點,例如瀏覽器的主介面,不管從多少個應用啟動瀏覽器,只會啟動主介面一次,其餘的情況都走onNewIntent,並且會清空主介面上面的其他頁面

④SingleInstance:此模式的activity只能單獨位於一個任務棧中,
*適合需要與程式分離的頁面
例如:鬧鈴提醒,將鬧鈴提醒與鬧鈴設定分離*

6.AlertDialog,popupWindow,Activity區別

二.service

1.Service 的生命週期

這裡寫圖片描述

2.Service的開啟,停止方式

啟動服務

Intent startIntent = new Intent(this,MyService.class);
startService(startIntent);

停止服務

Intent stopIntent = new Intent(this,MyService.class);
stopService(stopIntent);

3.Activity 怎麼和Service 繫結並進行資料互動

用Binder 物件連線活動和服務
在service中

private DownloadBinder downloadBinder = new DownloadBinder();
    class DownloadBinder extends Binder {
        public int getProgress() {
            return 0;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.v(TAG, "onBind: ");
        return downloadBinder;
    }

在Activity中建立ServiceConnection的匿名內部類,重寫onServiceConnected()和onServiceDisconnected()方法

private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        //在Activity中呼叫Binder中的方法
            MyService.DownloadBinder binder = (MyService.DownloadBinder) service;
            int progress = binder.getProgress();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

繫結服務

Intent startIntent = new Intent(this,MyService.class);
bindService(startIntent,connection,BIND_AUTO_CREATE);
//BIND_AUTO_CREATE 在活動和服務繫結後自動建立服務

解綁服務

unbindService(connection);

4.Service的生命週期與啟動方法由什麼區別?

startService():開啟Service,呼叫者退出後Service仍然存在。
bindService():開啟Service,呼叫者退出後Service也隨即退出。

5.怎麼在Activity 中啟動自己對應的Service

三.broadcast

1.請描述一下廣播BroadcastReceiver的理解

①是四大元件之一,主要用於接受APP傳送的廣播
②內部通訊實現機制:自定義廣播接收者BroadcastReceiver,並複寫onRecvice方法;通過android系統的Binder機制向AMS(Activity Manager Service)進行註冊;廣播發送者通過Binder機制向AMS傳送廣播;AMS查詢符合條件的(IntentFilter/Permission等)的BroadcastReceiver,將廣播發送到BroadcastReceiver(一般情況下是Activity)相應的訊息迴圈佇列中;訊息迴圈執行拿到此廣播,回撥BroadcastReceiver 中的onReceiver()方法
③廣播主要分為兩種型別

  • 標準廣播:是一種完全非同步執行的廣播,在廣播發出之後,所有的廣播接收器幾乎同時都會在同一時刻受到這條廣播訊息,這種廣播的效率比較高,但同時也意味著它是無法被截斷的
  • 有序廣播:是一個同步執行的廣播,廣播發出後,同一時刻只有一個廣播接收器能夠受到這條廣播訊息,當這個廣播接收器中的邏輯執行完畢後,廣播才會繼續傳遞。所有此時的廣播接收器是有先後順序的,優先順序高的先受到廣播,並且前面的廣播接收器還可以截斷正在傳遞的廣播,這樣後面的廣播接收器就無法接收到廣播訊息了

2.廣播的分類,本地廣播和全域性廣播有什麼差別

  • 全域性廣播:是跨應用廣播,利用Binder機制實現。即發出的廣播可以被其他任何應用程式接收到,並且也可以接收來自其他任何應用程式的廣播。這樣會很容易引起安全性問題
  • 本地廣播:是應用內廣播,利用Handler實現,利用了IntentFilter的match功能,提供訊息的釋出與接收功能,實現應用內通訊,效率比較高。本地廣播機制的發出的廣播只能在應用程式的內部進行傳遞,並且廣播接收器只能接收來自本應用程式發出的廣播。LocalBroadcastManager是本地廣播管理類
 public boolean sendBroadcast(Intent intent) {
        synchronized (mReceivers) {
            final String action = intent.getAction();
            final String type = intent.resolveTypeIfNeeded(
                    mAppContext.getContentResolver());
            final Uri data = intent.getData();
            final String scheme = intent.getScheme();
            final Set<String> categories = intent.getCategories();

            final boolean debug = DEBUG ||
                    ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
            if (debug) Log.v(
                    TAG, "Resolving type " + type + " scheme " + scheme
                    + " of intent " + intent);

            ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());
            if (entries != null) {
                if (debug) Log.v(TAG, "Action list: " + entries);

                ArrayList<ReceiverRecord> receivers = null;
                for (int i=0; i<entries.size(); i++) {
                    ReceiverRecord receiver = entries.get(i);
                    if (debug) Log.v(TAG, "Matching against filter " + receiver.filter);

                    if (receiver.broadcasting) {
                        if (debug) {
                            Log.v(TAG, "  Filter's target already added");
                        }
                        continue;
                    }

                    int match = receiver.filter.match(action, type, scheme, data,
                            categories, "LocalBroadcastManager");
                    if (match >= 0) {
                        if (debug) Log.v(TAG, "  Filter matched!  match=0x" +
                                Integer.toHexString(match));
                        if (receivers == null) {
                            receivers = new ArrayList<ReceiverRecord>();
                        }
                        receivers.add(receiver);
                        receiver.broadcasting = true;
                    } else {
                        if (debug) {
                            String reason;
                            switch (match) {
                                case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
                                case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
                                case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
                                case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
                                default: reason = "unknown reason"; break;
                            }
                            Log.v(TAG, "  Filter did not match: " + reason);
                        }
                    }
                }

                if (receivers != null) {
                    for (int i=0; i<receivers.size(); i++) {
                        receivers.get(i).broadcasting = false;
                    }
                    mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
                    if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
                        mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
                    }
                    return true;
                }
            }
        }
        return false;
    }

3.廣播使用的方式和場景

  • 建立一個廣播接收器,新建一個類讓它繼承BroadCast,並重寫onReceive()方法就行
  • 使用場景:
    1.App全域性監聽,這種主要用於在AndroidManifest中靜態註冊的廣播接收器,一般我們在收到該訊息後,需要做一些相應的動作,而這些動作與當前App的元件,比如Activity或者Service的是否執行無關,比如我們在整合第三方Push SDK時,一般都會新增一個靜態註冊的BroadcastReceiver來監聽Push訊息,當有Push訊息過來時,會在後臺做一些網路請求或者傳送通知等等。
    2.元件區域性監聽,這種主要是在Activity或者Service中使用registerReceiver()動態註冊的廣播接收器,因為當我們收到一些特定的訊息,比如網路連線發生變化時,我們可能需要在當前Activity頁面給使用者一些UI上的提示,或者將Service中的網路請求任務暫停。所以這種動態註冊的廣播接收器適合特定元件的特定訊息處理

4.在manifest 和程式碼中如何註冊和使用BroadcastReceiver

  • 動態註冊:在程式碼中註冊,動態廣播最好在Activity 的 onResume()註冊、onPause()登出,在onResume()註冊、onPause()登出是因為onPause()在App死亡前一定會被執行,從而保證廣播在App死亡前一定會被登出,從而防止記憶體洩露
  • 非 常駐系統,跟隨元件的生命週期變化而變化,元件結束,廣播結束。
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.ACTION_SHUTDOWN");
registerReceiver(new CommonBroadcastReceiver(),intentFilter);
  • 靜態註冊:在AndroidManifest.xml中註冊
  • 常駐系統,不受元件的生命週期影響,即便應用退出,廣播還是可以被接受,耗電,佔用記憶體
<receiver android:name=".broadcast.CommonBroadcastReceiver">
            <intent-filter>
                <!-- 關機廣播 -->
                <action android:name="android.intent.action.ACTION_SHUTDOWN" />
            </intent-filter>
</receiver>

5.廣播發送和接收的原理

  1. 繼承BroadcastReceiver,重寫onReceive()方法。
  2. 通過Binder機制向ActivityManagerService註冊廣播。
  3. 通過Binder機制向ActivityMangerService傳送廣播。
public abstract void sendBroadcast(Intent intent);
  1. ActivityManagerService查詢符合相應條件的廣播(IntentFilter/Permission)的
  2. BroadcastReceiver,將廣播發送到BroadcastReceiver所在的訊息佇列中。
  3. BroadcastReceiver所在訊息佇列拿到此廣播後,回撥它的onReceive()方法。

6.Binder機制

Android Binder是用來做程序通訊的,Android的各個應用以及系統服務都執行在獨立的程序中,它們的通訊都依賴於Binder。

7.Android裡的Intent傳遞的資料有大小限制嗎,如何解決?

Intent傳遞資料大小的限制大概在1M左右,超過這個限制就會靜默崩潰。處理方式如下:

程序內:EventBus,檔案快取、磁碟快取。
程序間:通過ContentProvider進行款程序資料共享和傳遞。

8.BroadcastReceiver的生命週期

BroadcastReceiver的onReceive()方法執行完成後,BroadcastReceiver的例項就會被銷燬。如果onReceive()方法在10s內沒有執行完畢,Android會認為改程式無響應。所以在BroadcastReceiver裡不能做一些比較耗時的操作,否則會彈出“Application NoResponse”對話方塊。特別說明的是,這裡不能使用子執行緒來解決 ,因為BroadcastReceiver的生命週期很短,子執行緒可能還沒有結束BroadcastReceiver就先結束了。BroadcastReceiver一旦結束,此時它所在的程序很容易在系統需要記憶體時被優先殺死,因為它屬於空程序。

四.contentProvider

1.談談你對ContentProvider的理解

ContentProvider管理android以結構化方式存放的資料。他以相對安全的方式封裝資料並且提供簡易的處理機制。Content provider提供不同程序間資料互動的標準化介面。保證被訪問資料的安全性。內容提供器可以選擇只對哪一部分資料進行共享,從而保證我們程式中的隱私資料不會有洩漏的風險。

2.說說ContentProvider、ContentResolver、ContentObserver 之間的關係

ContentResolver中提供了一系列的方法用於對資料進行CRUD,內容URI給內容提供器ContentProvider中的資料建立了唯一識別符號,ContentObserver監聽Uri資料的變化

①ContentProvider:管理資料,提供資料的增刪改查操作,資料來源可以是資料庫、檔案、XML
網路等。ContentProvider為這些資料提供了統一的介面,可以用來做程序間資料共享
②ContentResolver:ContentResolver可以不同的URI操作不同的ContentProvider中的資料庫,外部程序可以通過ContentResolver 與ContentProvider進行互動
③ContentObserver :觀察ContentProvider中的資料變化,並將變化通知給外界。