Android面試題整合(Android篇)

各位同學(xué),這是一篇面試總結(jié)文,把面試過程中遇到的問記錄下來,并附上如何回答。希望對正在面試或者將要面試的你有一些小幫助。
7f670aa6198e7af7bc8e4d11623154bc.jpeg
1.Glide中怎么實現(xiàn)圖片的加載進度條,Glide的緩存是怎么設(shè)計的?為什么要用弱引用?
1.將HTTP通訊組件替換成OkHttp
2.向OkHttp中添加一個自定義的攔截器
3.新建一個ProgressResponseBody類,并讓它繼承自O(shè)kHttp的ResponseBody,
然后在這個類當(dāng)中去編寫具體的監(jiān)聽下載進度的邏輯
---
1.內(nèi)存緩存:防止應(yīng)用重復(fù)將圖片數(shù)據(jù)讀取到內(nèi)存當(dāng)中,
  其中內(nèi)存緩存又包含 弱引用 和 LruCache 
2.硬盤緩存:防止應(yīng)用重復(fù)從網(wǎng)絡(luò)下載數(shù)據(jù)。
  硬盤緩存就是 DiskLruCache
---
1.可以保護當(dāng)前使用的資源不會被 LruCache 算法回收
2.即可以緩存正在使用的強引用資源,又不阻礙系統(tǒng)需要回收的無引用資源。
2.implementation 和 api的區(qū)別是什么?
加入我們項目中有A、B、C
第一種情況:
A implementation B
B implementation C
A可以直接訪問B中資源,但不能直接訪問C
第二種情況:
A implementation B
B api C
A 可以直接訪問B和C中的資源
---
使用implementation 依賴項配置代替 api 可以顯著縮短構(gòu)建時間,
因為這樣可以減少構(gòu)建系統(tǒng)需要重新編譯的模塊數(shù)。
3.事件分發(fā)的流程,以及怎么解決滑動沖突?mFirstTarget 為什么是一個鏈表?
---
Android事件分發(fā)流程 = Activity -> ViewGroup -> View
---
1,從外部攔截機制考慮
  例如:PullToRefreshView嵌套了ViewPager
2.子View如果不希望其父View攔截Touch事件時,
  調(diào)用getParent().requestDisallowInterceptTouchEvent
---
插入和刪除速度快,保留原有的物理順序
使內(nèi)存的利用率變高
4.自定義View需要經(jīng)歷哪幾個過程?
measure: 判斷是否需要重新計算View的大小,需要的話則計算;
layout: 判斷是否需要重新計算View的位置,需要的話則計算;
draw: 判斷是否需要重新繪制View,需要的話則重繪制。
5.A 跳轉(zhuǎn)到 B頁面,兩個頁面的生命周期怎么走?什么情況下A的stop()不會執(zhí)行。
1.A先執(zhí)行onPause
2.然后是B執(zhí)行onCreate -> onStart -> onResume
3.最后A執(zhí)行onStop
---
ActivityB為dialog式或者半透明背景 
6.Activity的4中啟動模式分別是什么,有什么不同?
standard:無論該活動有沒有加入棧,活動就會被創(chuàng)建。
singleTop:只要被創(chuàng)建的活動不位于棧的頂部,該活動就會被創(chuàng)建入棧。
singleTask:單任務(wù)模式。
singleInstance:被設(shè)置成singleInstance的Activity將會放入單獨的棧中。
7.okhttp中有幾個隊列?分別干什么用的?怎么取消一個請求?
兩個隊列
---
等待隊列和執(zhí)行任務(wù)的隊列
---
OkHttp提供了cancel方法
ps:不同的失敗類型返回的IOException e 不一樣,
可以通過e.toString 中的關(guān)鍵字來區(qū)分不同的錯誤類型
8.Rxjava中map和flatMap有什么區(qū)別,都用過什么操作符。
map:對數(shù)據(jù)進行變換后,可以返回任意值。是1對1進行的。
flatMap:對數(shù)據(jù)變換后,返回ObservableSource對象。
        可以對數(shù)據(jù)進行一對多,多對多的變換。并不保證數(shù)據(jù)
        有序。
concatMap:與flatMap使用基本一致,它可以保證數(shù)據(jù)有序
---(用過的操作符)---
1.創(chuàng)建操作符:
  just():此操作符的作用是將傳入的數(shù)據(jù)依次發(fā)送出去.最多可以傳10個參數(shù)
  fromIterable() :此操作符的作用是將傳入的數(shù)組集合按腳標依次發(fā)送出去
  fromArray() :對一個數(shù)組集合進行觀察,把數(shù)組一次性發(fā)給觀察者
  Range():作用發(fā)送指定范圍的序列,可指定范圍.作用類似intervalRange,但不同的是range是無延遲發(fā)送
  interval():這個相當(dāng)于定時器,用它可以取代CountDownTimer。
    它會按照設(shè)定的間隔時間,每次發(fā)送一個事件,發(fā)送的事件序列:默認從0開始,無限遞增的整數(shù)序列
2.轉(zhuǎn)換操作符:
  map():被觀察者轉(zhuǎn)換器,通過指定一個Funcation對象,將Observable
    轉(zhuǎn)換成新的Observable對象并發(fā)射,觀察者會收到新的Observable并處理
  flatMap():把Observable的發(fā)射事件集合轉(zhuǎn)換成新的Observable集合
  concatMap() :與flatMap唯一不同的是concat能保證Observer接收到Observable集合發(fā)送事件的順序
  buffer():把發(fā)射數(shù)據(jù)按照一定間隔分成若干段。按每段的數(shù)據(jù)轉(zhuǎn)換成新的Observable,
    這個Observable把一段數(shù)據(jù)一次性發(fā)射出去。
3.合并操作符 :
  merge():把多個Observable合并成一個進行發(fā)射(并行無序)
  concat ():把多個Observable合并成一個進行發(fā)射(串行有序)
  concatDelayError()/mergeDelayError():可以使onError事件推遲到其它被觀察者發(fā)送事件結(jié)束后在再觸發(fā)
  zip():把多個Observable合并后,并且把這些Observable的數(shù)據(jù)進行轉(zhuǎn)換再發(fā)射出去。
    轉(zhuǎn)換之后的數(shù)據(jù)數(shù)目由最短數(shù)據(jù)長度的那個Observable決定。
  collect():把 Observable(被觀察者)發(fā)送的事件收集到一個數(shù)據(jù)結(jié)構(gòu)中
  startWith()/startWithArray():在一個被觀察者發(fā)送時間前,追加發(fā)送一些數(shù)據(jù)/一個新的被觀察者
  count():統(tǒng)計被觀察者發(fā)送事件數(shù)量
4.功能操作符:
  subscribe():連接被觀察者和觀察者
  delay():延遲發(fā)送事件
  do :系列操作符
     *doOnEach() :當(dāng)Observable每發(fā)送一次事件就會調(diào)用一次(包含onNext(),onError(),onComplete())
     * doOnNext(): 執(zhí)行 onNext()前調(diào)用
     * doAfterNext(): 執(zhí)行onNext()后調(diào)用
     * doOnComplete():執(zhí)行onComplete()前調(diào)用
     * doOnError():執(zhí)行 onError()前調(diào)用
     * doOnTerminate(): 執(zhí)行終止(無論正常發(fā)送完畢/異常終止)
     * doFinally(): 最后執(zhí)行
     * doOnSubscribe() :觀察者訂閱是調(diào)用
     * doOnUnScbscribe(): 觀察者取消訂閱時調(diào)用
  onErrorReturn() :可以捕獲錯誤。發(fā)送一個特殊事件,并且正常終止.注意后面的事件不會再發(fā)送
  onExceptionResumeNext():遇到錯誤時發(fā)送一個新的Observable 。并且正常終止.注意原Observable后面的事件不會再發(fā)送
  retry() :出現(xiàn)錯誤時,讓被觀察者重新發(fā)送數(shù)據(jù)
  repeat() :repeat操作符的作用是重復(fù)發(fā)射 observable的數(shù)據(jù)序列,可以使無限次也可以是指定次數(shù).不傳時為重復(fù)無限次
  debounce() :一定的時間內(nèi)沒有操作就會發(fā)送事件(只會發(fā)送最后一次操作的事件)。
  subscribeOn():發(fā)送事件的線程
  observerOn():接收事件的線程
5.過濾操作符:
  filter() :對被觀察者發(fā)送的事件做過濾操作。只有符合篩選條件的事件才會被觀察者所接收。
  distinct():去重
  skip():把Observable發(fā)射的數(shù)據(jù)過濾點掉前n項。
  take():只能接收n事件
  elementAt():只發(fā)射第n項數(shù)據(jù).(第n項,第N項不存在時默認值)
  ignoreElements() :不管發(fā)射的數(shù)據(jù).只希望在它完成時和遇到錯誤時收到通知
  ofType() :只發(fā)送指定類型數(shù)據(jù)。
  sample():在某段時間內(nèi),只發(fā)送該段時間內(nèi)最新(最后)1次事件
  firstElement()/lastElement():選取第一個元素/最后一個元素
9.如果Rxjava組合發(fā)送任務(wù),中間任務(wù)出現(xiàn)異常,其他任務(wù)該怎么處理。
使用concatError()/mergeDelayError()事件,
可以使onError事件推遲到其它被觀察者發(fā)送事件結(jié)束后在再觸發(fā)
10.哪個場景會發(fā)生內(nèi)存泄露?內(nèi)存泄露怎么檢測?以及l(fā)eak cannery內(nèi)部原理是什么?為什么新版本的不需要在Application中注冊了?
---哪個場景會發(fā)生內(nèi)存泄露---
1. 資源性對象未關(guān)閉(比如 Cursor、File 文件等)
2. 注冊對象未注銷
3. 類的靜態(tài)變量持有大數(shù)據(jù)對象(靜態(tài)變量長期維持對象的引用,阻止垃圾回收,如果靜態(tài)變量持有大的數(shù)據(jù)對象,
   如Bitmap 等,就很容易引起內(nèi)存不足等問題。)
4. 非靜態(tài)內(nèi)部類的靜態(tài)實例(非靜態(tài)內(nèi)部類會維持一個到外部類實例的引用,如果非靜態(tài)內(nèi)部類的實例是靜態(tài)的,
   就會間接長期維持著外部類的引用,阻止被系統(tǒng)回收。)
5. Handler臨時性內(nèi)存泄漏
    (Message 發(fā)出之后存儲在 MessageQueue 中,有些 Message 也不是馬上就被處理到。
    在Message 中存在一個 target,它是 Handler 的一個引用,Message 在 Queue 中存在的時間過長,
    就會導(dǎo)致 Handler 無法被回收。如果 Handler 是非靜態(tài)的,
    則會導(dǎo)致 Activity 或者 Service不會被回收。)
    解決方法:
    1)使用一個靜態(tài) Handler 內(nèi)部類,然后對 Handler 持有的對象使用弱引用,
       這樣在回收時,也可以回收 Handler 持有的對象。
    2)在 Activity 的 Destroy 或者 Stop 時,應(yīng)該移除消息隊列中的消息,
       避免 Looper 線程的消息隊列中有待處理的消息需要處理。
6. 容器中的對象沒清理造成內(nèi)存泄漏
    通常把一些對象的引用加入集合中,在不需要該對象時,如果沒有把它的引用從集合中清理掉,
    這個集合就會越來越大。如果這個集合是 static,情況就更嚴重。
7. WebView
    通常解決這個問題的辦法是為 WebView 開啟獨立的一個進程,
    使用AIDL 與應(yīng)用的主進程進行通信,WebView 所在的進程可以根據(jù)業(yè)務(wù)的需要選擇
    合適的時機進行銷毀,達到正常釋放內(nèi)存的目的。
---內(nèi)存泄露怎么檢測---
集成Android LeakCanary
直接在Application中使用,然后運行APP就會自動檢測,檢測到會在另一個APP上通知
---內(nèi)部原理---
監(jiān)聽Activity生命周期->onDestroy以后延遲5秒判斷Activity有沒有被回收
->如果沒有回收,調(diào)用GC,再此判斷是否回收,如果還沒回收,則內(nèi)存泄露了,反之,沒有泄露。
整個框架最核心的問題就是在什么時間點如何判斷一個Activity是否被回收了。
---為什么新版本的不需要在Application中注冊了---
1,由于我們添加了LeakCanary2的依賴,而在他依賴的leakcanary-object-watcher-android工程中,注冊了一個provider。
2,當(dāng)app進程啟動的時候,會自動創(chuàng)建注冊這個provider,并執(zhí)行其中的onCreate方法。
3,在這個onCreate方法中,調(diào)用了LeakCanary的install方法,創(chuàng)建各自的watcher,并注冊監(jiān)聽了application的ActivityLifecycleCallback。
11.手機適配問題怎么處理,都有什么方案。
1.使用布局元素自適應(yīng)尺寸
RelativeLayout + LinearLayout + ConstraintLayout
2.屏幕分辨率限定符適配(簡單說,就是窮舉市面上所有的Android手機的寬高像素值)
3.smallestWidth限定符適配(sw限定符適配)(插件 ScreenMatch)
  sw限定符適配是寬高限定符的升級版,他解決了寬高限定符容錯機制差的問題,
  是目前主流的適配方式之一。
4.使用 Nine-Patch 圖片。
5.代碼動態(tài)設(shè)置尺寸。
12.Android9 10 11 都更新了什么新特性?新版本中無法獲取IMEI怎么處理。
Android9:
  1.自適應(yīng)電池
  2.黑暗模式
  3.新截圖快捷方式
  4.一個新的Home按鈕
  5.新的手勢導(dǎo)航
Android10:
  1. 暗黑模式
  2. 隱私增強(如您可以選擇應(yīng)用程序在后臺運行時是否可以訪問該位置)
  3.超級鎖定模式
  4.屏幕錄制
  5.面部識別
  6.限制程序訪問剪貼板
Android11:
1.短信更新改進
2.隱私和權(quán)限(新增了關(guān)于位置、麥克風(fēng)和攝像頭的一次性權(quán)限許可)
3.內(nèi)置屏幕錄制
4.適配不同設(shè)備(折疊手機)
5.網(wǎng)絡(luò)優(yōu)化(通過5G連接到無線網(wǎng)絡(luò))
---
Android 10 中官方明確說明第三方應(yīng)用無法獲取到IMEI碼
Android 10 以下的版本,需要申請READ_PHONE_STATE權(quán)限。
13.數(shù)據(jù)序列化有那倆種方式,Serialization和Parcelable區(qū)別,如果持久化需要用哪一個?
序列化:將對象的狀態(tài)信息轉(zhuǎn)換為可以存儲或傳輸?shù)男问降倪^程
Serializable:是Java的實現(xiàn)方式,會頻繁的IO操作,所以消耗比較大,但是實現(xiàn)方式簡單
Parcelable:是Android提供的方式,效率比較高,但是實現(xiàn)起來復(fù)雜一些 
持久化需要用Serializable
14.組件化怎么分層,各個組件之間怎么通信。
1.宿主層:不做具體的項目功能實現(xiàn),只負責(zé)集成業(yè)務(wù)模塊,組裝成一個完整的APP;
2.業(yè)務(wù)模塊層:將項目的每個大功能模塊拆分成的一個一個單獨的module,可獨立運行,同產(chǎn)品的不同項目也可復(fù)用;
3.業(yè)務(wù)組件層:用于業(yè)務(wù)模塊間調(diào)用,例如支付組件 、地圖組件、分享組件等等;
4.基礎(chǔ)組件層:基礎(chǔ)組件層,與業(yè)務(wù)無關(guān),與項目也無關(guān),所有項目都可以全部復(fù)用,
  包含了各種開源庫以及和業(yè)務(wù)無關(guān)的各種自研工具庫;
---
各個組件之間通過`阿里的ARouter`通信
15.怎防止程序崩潰,如果已經(jīng)到了Thread.UncaughtExceptionHandler是否可以讓程序繼續(xù)運行。
我們可以給應(yīng)用設(shè)置我們自定義的UncaughtExceptionHandler
---
子線程發(fā)生了未捕獲異常不會導(dǎo)致Crash(子線程被終止了,主線程還在運行)
主線程發(fā)生了未捕獲異常會導(dǎo)致ANR(主線程已經(jīng)被終止了)。
16.Handler Looper mesaageQueue message 之間的關(guān)系。
 Looper:相當(dāng)于消息的載體
 ? 它的內(nèi)部有一個消息隊列,也就是MessageQueue,Handler發(fā)送的所有消息都會走向這個消息隊里。
 ? 它的Looper.loop方法是一個死循環(huán),不斷的從消息隊列MessageQueue中取出消息。如果有消息存在就處理該消息,否則就阻塞。
 messageQueue :就是一個消息隊列,可以向其中添加消息并處理消息。
 handler:其實就是發(fā)送消息處理消息的封裝。它與Looper相關(guān)聯(lián),也就是說在Handler的內(nèi)部可以找到Looper,
    找到了Looper就找到了相應(yīng)的消息隊列。因此Handler發(fā)送的消息都會走向MessageQueue。

其實就是:
Handler負責(zé)發(fā)送消息和接收Looper傳過來的消息,并根據(jù)消息處理相應(yīng)邏輯
Looper負責(zé)接收Handler發(fā)送過來的消息,并將該消息回傳給Handler自己。
MessageQueue只是相當(dāng)于一個消息容器
17.子線程一定不能更新ui么?什么時候可以?什么時候不可以。檢測邏輯是在什么階段初始化的。
ViewRootImpl對象是在onResume方法回調(diào)之后才創(chuàng)建,那么就說明了為什么在生命周期的onCreate方法里,
甚至是onResume方法里都可以實現(xiàn)子線程更新UI,因為此時還沒有創(chuàng)建ViewRootImpl對象,
并不會進行是否為主線程的判斷;
18.ANR發(fā)生的原理是什么, 怎么排查。
1.5秒內(nèi)無法對輸入事件(按鍵及觸摸)做出響應(yīng)
2.廣播接收器無法在10秒內(nèi)結(jié)束運行
3.前臺服務(wù)20秒內(nèi),后臺服務(wù)在200秒內(nèi)沒有執(zhí)行完畢。
4.ContentProvider的publish在10s內(nèi)沒進行完。
---怎么排查
分析辦法一:Log
分析辦法二:traces.txt
---原因
1.主線程阻塞或主線程數(shù)據(jù)讀取
  解決辦法:避免死鎖的出現(xiàn),使用子線程來處理耗時操作或阻塞任務(wù)。
2.CPU滿負荷,I/O阻塞
  解決辦法:文件讀寫或數(shù)據(jù)庫操作放在子線程異步操作。
3.內(nèi)存不足
  解決辦法:防止內(nèi)存泄漏,優(yōu)化內(nèi)存使用
4.各大組件ANR
  各大組件生命周期中也應(yīng)避免耗時操作,注意BroadcastReciever的onRecieve()、
  后臺Service和ContentProvider也不要執(zhí)行太長時間的任務(wù)。
19.程序怎么?;睢?/h6>
1:開啟系統(tǒng)電池白名單。
2:引導(dǎo)用戶在設(shè)置里,將app加入后臺運行白名單。
3:開啟前臺服務(wù)。
20.說下路由ARoute的實現(xiàn)原理,怎么處理頁面過多內(nèi)存占用過大問題。
1.路由框架會在項目的編譯期通過注解處理器掃描所有添加@Route注解的Activity類,
2.然后會在編譯時期通過apt將Route注解中的path地址和Activity.class文件映射關(guān)系保存到它自己生成的java文件中
3.然后app進程啟動的時候會加載這些類文件,把保存這些映射關(guān)系的數(shù)據(jù)讀到內(nèi)存里(保存在map里)
4.然后在進行路由跳轉(zhuǎn)的時候,通過build()方法傳入要到達頁面的路由地址,
  ARouter會通過它自己存儲的路由表找到路由地址對應(yīng)的Activity.class,
  然后new Intent(context, activity.Class)
5.當(dāng)調(diào)用ARouter的withString()方法它的內(nèi)部會調(diào)用intent.putExtra(String name, String value)
6.調(diào)用navigation()方法,它的內(nèi)部會調(diào)用startActivity(intent)進行跳轉(zhuǎn)
---怎么處理頁面過多內(nèi)存占用過大問題
知道的幫我貼個鏈接,謝了。
21.線程池都什么時候用,怎么創(chuàng)建,構(gòu)造函數(shù)中的參數(shù)分別代表什么意思?
線程頻繁地創(chuàng)建與銷毀

---怎么創(chuàng)建---
Executors.newCachedThreadPool();
*執(zhí)行很多短期異步的小程序或者負載較輕的服務(wù)器
Executors.newFixedThreadPool(5);
*執(zhí)行長期的任務(wù),性能好很多
Executors.newSingleThreadExecutor();
*一個任務(wù)一個任務(wù)執(zhí)行的場景
Executors.newScheduledThreadPool(3);
*周期性執(zhí)行任務(wù)的場景

---構(gòu)造函數(shù)中的參數(shù)---
corePoolSize:該線程池中核心線程的數(shù)量。
maximumPoolSize:該線程池中最大線程數(shù)量。
keepAliveTime:非核心線程空閑時間
unit:上面時間屬性的單位
workQueue:任務(wù)隊列,后面詳述。
threadFactory:線程工廠,可用于設(shè)置線程名字等等,一般無須設(shè)置該參數(shù)。
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
}
22.進程優(yōu)先級。
前臺進程
可見進程
服務(wù)進程
后臺進程
空進程
23.本地廣播和正常廣播的區(qū)別。
本地廣播:發(fā)送的廣播事件不被其他應(yīng)用程序獲取,也不能響應(yīng)其他應(yīng)用程序發(fā)送的廣播事件。
  本地廣播只能被動態(tài)注冊,不能靜態(tài)注冊。動態(tài)注冊或方法時需要用到LocalBroadcastManager。
全局廣播:發(fā)送的廣播事件可被其他應(yīng)用程序獲取,也能響應(yīng)其他應(yīng)用程序發(fā)送的廣播事件
  (可以通過 exported–是否監(jiān)聽其他應(yīng)用程序發(fā)送的廣播在清單文件中控制)
  全局廣播既可以動態(tài)注冊,也可以靜態(tài)注冊。
23.Activity啟動流程,Launcher啟動流程。
---android中activity啟動流程
一.Launcher通過Binder進程間通信機制通知ActivityManagerService,它要啟動一個Activity;
二.ActivityManagerService通過Binder進程間通信機制通知Launcher進入Paused狀態(tài);
三.Launcher通過Binder進程間通信機制通知ActivityManagerService,它已經(jīng)準備就緒進入Paused狀態(tài),
    于是ActivityManagerService就創(chuàng)建一個新的進程,用來啟動一個ActivityThread實例,即將要啟動的Activity就是在這個ActivityThread實例中運行;
四.ActivityThread通過Binder進程間通信機制將一個ApplicationThread類型的Binder對象傳遞給ActivityManagerService,以便以后ActivityManagerService能夠通過這個Binder對象和它進行通信;
五.ActivityManagerService通過Binder進程間通信機制通知ActivityThread,現(xiàn)在一切準備就緒,它可以真正執(zhí)行Activity的啟動操作了。
---Launcher的啟動由三部分啟動:
    SystemServer完成啟動Launcher Activity的調(diào)用
    Zygote()進行Launcher進程的Fork操作
    進入ActivityThread的main(),完成最終Launcher的onCreate操作
24.mvvp 和mvp的區(qū)別,細節(jié)里怎么實現(xiàn)的雙向綁定。
MVC:View觸發(fā)事件,controller響應(yīng)并處理邏輯,調(diào)用Model,Model處理完成后將數(shù)據(jù)發(fā)送給View,View更新。
MVP:以Presenter為核心,負責(zé)從model獲取數(shù)據(jù),并填充到View中。
MVVM:View與VM保持同步,View綁定到VM的屬性上,如果VM數(shù)據(jù)發(fā)生變化,通過數(shù)據(jù)綁定的方式,View會自動更新視圖;VM同樣也暴露出Model中的數(shù)據(jù)。
---
可通過databing實現(xiàn)雙向綁定。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容