Android基礎篇

背景

最近在準備面試麻蹋,結合之前的工作經驗和近期在網上收集的一些面試資料皂贩,準備將Android開發(fā)崗位的知識點做一個系統(tǒng)的梳理菲驴,整理成一個系列:Android應用開發(fā)崗 面試匯總会傲。本系列將分為以下幾個大模塊:
Java基礎篇混卵、Java進階篇题翰、常見設計模式
Android基礎篇恶阴、Android進階篇诈胜、性能優(yōu)化
網絡相關、數(shù)據(jù)結構與算法
常用開源庫冯事、Kotlin焦匈、Jetpack

注1:以上文章將陸續(xù)更新,直到我找到滿意的工作為止昵仅,有跳轉鏈接的表示已發(fā)表的文章缓熟。
注2:該系列屬于個人的總結和網上東拼西湊的結果,每個知識點的內容并不一定完整摔笤,有不正確的地方歡迎批評指正够滑。
注3:部分摘抄較多的段落或有注明出處。如有侵權吕世,請聯(lián)系本人進行刪除彰触。

Fragment相關

Activity與Fragment之間生命周期比較

Activity于Fragment的生命周期的不同主要表現(xiàn)在onCreateonDestroy兩個生命周期方法中:

  • 在Activity的onCreate方法回調時,在回調期間命辖,F(xiàn)ragment首先會執(zhí)行
    onAttach()-->onCreate()-->onCreateView()-->onActivityCreated()
  • 在Activity的onDestroy()回調時况毅,在回調期間,F(xiàn)ragment首先會執(zhí)行onDestroyView()-->onDestroy()-->onDetach()

Fragment 如何實現(xiàn)類似 Activity 棧的壓棧和出棧效果尔艇?

Fragment 的事物管理器(FragmentManager )內部維持了一個雙向鏈表結構尔许,該結構可以記錄我們每次 add 的Fragment 和 replace 的 Fragment,然后當我們點擊 back 按鈕的時候會自動幫我們實現(xiàn)退棧操作终娃。

Fragment與Activity之間是如何傳值的味廊?

  • Activity向Fragment傳值:將要傳的值,放到bundle對象里尝抖,在Activity中創(chuàng)建該Fragment的對象fragment毡们,
    通過調用 fragment.setArguments()傳遞到fragment中;在該Fragment中通過調用getArguments()得到bundle對象昧辽,就能得到里面的值衙熔。
  • Fragment向Activity傳值:在Activity中拿到Fragment的實例,通過回調的方式搅荞,在Activity中實現(xiàn)Fragment的回調红氯。
  • 通過在Activity中生成ViewModel,在Fragment使用該ViewModel

Fragment懶加載

為什么要實現(xiàn)懶加載咕痛?

在沒有添加懶加載之前痢甘,只要使用 add+show+hide 的方式控制并顯示 Fragment, 那么不管 Fragment 是否嵌套,在初始化后茉贡,如果只調用了add+show塞栅,同級下的 Fragment 的相關生命周期函數(shù)都會被調用。且調用的生命周期函數(shù)如下所示:(不管該Fragment是否用戶可見腔丧,都會調用以下函數(shù)放椰,常見在viewpager中)
onAttach -> onCreate -> onCreatedView -> onActivityCreated -> onStart -> onResume

因此作烟,為了避免性能和流量的浪費,需要對當前不可見的Fragment進行懶加載處理砾医,即Fragment真正被用戶看到時才開始去加載數(shù)據(jù)拿撩。

add+show+hide 模式下的老方案

場景:通過show+hide方法控制兩個fragment的顯示,A和B如蚜,當從A切換到B時压恒,兩個Fragment的可見狀態(tài)發(fā)生了改變,F(xiàn)ragment會回調onHiddenChanged()方法错邦,A中isHidden()方法的值為 true探赫,B中為false。
方案:

  • 只要通過 show+hide 方式控制 Fragment 的顯隱兴猩,那么在第一次初始化后期吓,F(xiàn)ragment 任何的生命周期方法都不會調用早歇,只有 onHiddenChanged 方法會被調用倾芝。
  • 另,假如我們要在 add+show+hide 模式下控制 Fragment 的懶加載箭跳,我們只需要做這兩步:

因此

  • 1晨另、我們需要在 onResume() 函數(shù)中調用 isHidden() 函數(shù),來處理默認顯示的 Fragment谱姓;
  • 2借尿、在 onHiddenChanged 函數(shù)中控制其他不可見的Fragment,即:
abstract class LazyFragment:Fragment(){
    private var isLoaded = false //控制是否執(zhí)行懶加載
    override fun onResume() {
        super.onResume()
        judgeLazyInit()
    }
    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        judgeLazyInit()
    }
    private fun judgeLazyInit() {
        if (!isLoaded && !isHidden()) {
            lazyInit()
            isLoaded = true
        }
    }
     override fun onDestroyView() {
        super.onDestroyView()
        isLoaded = false
    }
    //懶加載方法
    abstract fun lazyInit()
}

ViewPager+Fragment 模式下的老方案

ViewPager+Fragment 模式下的老方案
使用傳統(tǒng)方式處理 ViewPager 中 Fragment 的懶加載屉来,我們需要控制 setUserVisibleHint(boolean isVisibleToUser) 函數(shù)路翻,該函數(shù)與之前我們介紹的 onHiddenChanged() 作用非常相似,都是通過傳入的參數(shù)值來判斷當前 Fragment 是否對用戶可見茄靠,只是 onHiddenChanged() 是在 add+show+hide 模式下使用茂契,而 setUserVisibleHint 是在 ViewPager+Fragment 模式下使用。public void setUserVisibleHint(boolean isVisibleToUser) {}
因此:

abstract class LazyFragment : Fragment() {
    //是否執(zhí)行懶加載
    private var isLoaded = false
    //當前Fragment是否對用戶可見
    private var isVisibleToUser = false

    /**
     * 當使用ViewPager+Fragment形式會調用該方法時慨绳,setUserVisibleHint會優(yōu)先Fragment生命周期函數(shù)調用掉冶,
     * 所以這個時候就,會導致在setUserVisibleHint方法執(zhí)行時就執(zhí)行了懶加載,
     * 而不是在onResume方法實際調用的時候執(zhí)行懶加載脐雪。所以需要這個變量
     */
    private var isCallResume = false
    override fun onResume() {
        super.onResume()
        isCallResume = true
        judgeLazyInit()
    }
    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        isVisibleToUser = !hidden
        judgeLazyInit()
    }
    private fun judgeLazyInit() {
        if (!isLoaded && isVisibleToUser && isCallResume) {
            lazyInit()
            Log.d(TAG, "lazyInit:!!!!!!!")
            isLoaded = true
        }
    }
    //在Fragment銷毀View的時候厌小,重置狀態(tài)
    override fun onDestroyView() {
        super.onDestroyView()
        isLoaded = false
        isVisibleToUser = false
        isCallResume = false
    }
    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        this.isVisibleToUser = isVisibleToUser
        judgeLazyInit()
    }
    abstract fun lazyInit()
}

Androidx 下的懶加載

雖然之前的方案就能解決輕松的解決 Fragment 的懶加載,但這套方案有一個最大的弊端战秋,就是不可見的 Fragment 執(zhí)行了 onResume() 方法璧亚。onResume 方法設計的初衷,難道不是當前 Fragment 可以和用戶進行交互嗎脂信?你他媽既不可見癣蟋,又不能和用戶進行交互拐袜,你執(zhí)行 onResume 方法干嘛?
基于此問題梢薪,Google 在 Androidx 在 FragmentTransaction 中增加了 setMaxLifecycle 方法來控制 Fragment 所能調用的最大的生命周期函數(shù)蹬铺。即Fragment被用戶可見和可操作時才調用onResume方法:

add+show+hide 模式下的新方案

通過FragmentTransaction 設置setMaxLifecycle的值:setMaxLifecycle(Lifecycle.State.STARTED),可以使Fragment生命周期降級到onStart。

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
homefragment = new HomeFragment();
ft.add(R.id.fl_container, homefragment);
ft.setMaxLifecycle(homefragment, Lifecycle.State.STARTED);
ft.commit();

ViewPager+Fragment 模式下的老方案

該場景下秉撇,通過調用FragmentStatePagerAdapter中的setPrimaryItem(FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)
注:該方法最終也是調setMaxLifecycle()甜攀。

以上兩種方式只需要在onResume中增加是否已經加載過數(shù)據(jù)的判斷,來決定是否需要執(zhí)行初次加載琐馆。
參考鏈接

Service相關

簡介:

Service(服務)是一個可以在后臺執(zhí)行長時間運行操作而沒有用戶界面的應用組件规阀。Service是運行在主線程中的(跟Activity同一個線程),不能進行耗時操作瘦麸。我們一般都是在Service中創(chuàng)建一個新的線程來處理一些耗時工作谁撼,這樣就不會阻塞主線程。

啟動Service的兩種方式

  • startService方式啟動
    如果運行在后臺的Service甚至不需要和UI(主)線程間進行交互滋饲,這種情況下厉碟,一般是調用startService來啟動Service。通過 startService啟動屠缭,Service 會經歷 onCreate 到 onStartCommand箍鼓,然后處于運行狀態(tài),stopService的時候調用 onDestroy方法呵曹。 如果是調用者自己直接退出而沒有調用 stopService 的話款咖,Service 會一直在后臺運行。
  • bindService方式啟動
    兩個不同進程間通信 或者 某個應用中Service方法的暴露出去(同個進程間)奄喂,一般是調用bindService來啟動Service铐殃。通過 bindService啟動,Service 會運行 onCreate跨新,然后是調用 onBind富腊, 這個時候調用者和 Service綁定在一起。調用者退出了玻蝌,Srevice 就會調用 onUnbind->onDestroyed 方法蟹肘。
    所謂綁定在一起就共存亡了,調用者也可以通過調用 unbindService 方法來停止服務。

Service的生命周期

image.png

回調方法說明

  • onCreate:如果多次執(zhí)行了Context的startService方法啟動Service俯树,Service方法的onCreate方法只會在第一次創(chuàng)建Service的時候調用一次帘腹,以后均不會再次調用。我們可以在onCreate方法中完成一些Service初始化相關的操作
  • onStartCommand:如果多次執(zhí)行了Context的startService方法许饿,那么Service的onStartCommand方法也會相應的多次調用阳欲。onStartCommand方法很重要,我們在該方法中根據(jù)傳入的Intent參數(shù)進行實際的操作,比如會在此處創(chuàng)建一個子線程用于下載數(shù)據(jù)或播放音樂等
  • onBind:Service中的onBind方法是個抽象方法球化,所以Service類本身就是一個抽象類秽晚,也就是說onBind方法必須要重寫,即使用不到筒愚。通過startService使用Service時赴蝇,我們在重寫onBind方法時,只需要將其返回值設為null即可巢掺。onBind方法主要是用于給bindService方法調用Service時才使用到句伶。
  • onDestroy:Service銷毀時回調函數(shù)

常見面試題

1、什么是 IntentService陆淀?有何優(yōu)點考余?

  • IntentService 是 Service 的子類,比普通的 Service 增加了額外的功能轧苫。
    先看 Service 本身存在兩個問題:
  • Service 不會專門啟動一條單獨的進程楚堤,Service 與它所在應用位于同一個進程中;
  • Service 也不是專門一條新線程含懊,因此不應該在 Service 中直接處理耗時的任務身冬;
  • IntentService 特征
    1、會創(chuàng)建獨立的 worker 線程來處理所有的 Intent 請求绢要;
    2吏恭、會創(chuàng)建獨立的 worker 線程來處理 onHandleIntent()方法實現(xiàn)的代碼拗小,無需處理多線程問題重罪;
    3、所有請求處理完成后哀九,IntentService 會自動停止剿配,無需調用 stopSelf()方法停止 Service;
    4阅束、為Service 的 onBind()提供默認實現(xiàn)呼胚,返回 null;
    5息裸、為Service 的 onStartCommand 提供默認實現(xiàn)蝇更,將請求 Intent 添加到隊列中;

2呼盆、怎么保證應用盡可能不被殺死

  • 通過保證Service不被銷毀的方式(提高Service所在進程的優(yōu)先級)
  • 手機廠商將應用加入白名單

保證Service不被銷毀

  • 1年扩、在onStartCommand方法中將flag設置為START_STICKY,即return Service.START_STICKY;
  • 2访圃、在xml中設置了android:priority
//設置服務的優(yōu)先級為MAX_VALUE
 <service android:name=".MyService"
          android:priority="2147483647" >
 </service>
  • 3厨幻、在onStartCommand方法中設置為前臺進程
    通過設置一個狀態(tài)欄顯示來實現(xiàn)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Notification notification = new Notification(R.mipmap.ic_launcher, "服務正在運行",System.currentTimeMillis());
    Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,notificationIntent,0);
    RemoteViews remoteView = new RemoteViews(this.getPackageName(),R.layout.notification);
    remoteView.setImageViewResource(R.id.image, R.mipmap.ic_launcher);
    remoteView.setTextViewText(R.id.text , "Hello,this message is in a custom expanded view");
    notification.contentView = remoteView;
    notification.contentIntent = pendingIntent;
    startForeground(1, notification);
    return Service.START_STICKY;
}
  • 4、在onDestroy方法中重啟service
@Override
public void onDestroy() {
    super.onDestroy();
    startService(new Intent(this, MyService.class));
}
  • 5、用AlarmManager.setRepeating(…)方法循環(huán)發(fā)送鬧鐘廣播,接收的時候調用service的onstart方法
    Intent intent = new Intent(MainActivity.this,MyAlarmReciver.class);
    PendingIntent sender = PendingIntent.getBroadcast( MainActivity.this, 0, intent, 0);

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.add(Calendar.SECOND, 1);
    AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
    //重復鬧鐘
    /**
     * @param triggerAtMillis t 鬧鐘的第一次執(zhí)行時間况脆,以毫秒為單位
     * @param intervalMillis 表示兩次鬧鐘執(zhí)行的間隔時間饭宾,也是以毫秒為單位
     * @param operation 綁定了鬧鐘的執(zhí)行動作,比如發(fā)送一個廣播格了、給出提示等等
     */
    am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 2 * 1000, sender);

相關面試題

Broadcast Receiver相關

如何注冊 BroadcastReceiver

在清單文件中注冊廣播接收者稱為靜態(tài)注冊看铆,在代碼中注冊稱為動態(tài)注冊。

  • 靜態(tài)注冊的廣播接收者只要 app 在系統(tǒng)中運行則一直可以接收到廣播消息盛末,
  • 動態(tài)注冊的廣播接收者當注冊的 Activity 或者 Service 銷毀了那么就接收不到廣播了性湿。
    靜態(tài)注冊:在清單文件中進行如下配置
<receiver android:name=".BroadcastReceiver1" > 
     <intent-filter>
        <action android:name="android.intent.action.CALL" > </action>
      </intent-filter> 
</receiver>

動態(tài)注冊:在代碼中進行如下注冊

receiver = new BroadcastReceiver(); 
IntentFilter intentFilter = new IntentFilter(); 
intentFilter.addAction(CALL_ACTION);
context.registerReceiver(receiver, intentFilter);

Android 引入廣播機制的用意?

  • 程序間互通消息(例如在自己的應用程序內監(jiān)聽系統(tǒng)來電)
  • 效率上(參考 UDP 的廣播協(xié)議在局域網的方便性)
  • 設計模式上(反轉控制的一種應用,類似觀察者模式)

兩種注冊各有什么特點

靜態(tài)注冊

  • 常駐满败,當應用程序關閉后如果有信息廣播來肤频,程序也會被系統(tǒng)調用,自己運行算墨。
  • 無需擔憂廣播接收器是否被關閉宵荒,只要設備是開啟狀態(tài),廣播接收器就是打開著的净嘀。

動態(tài)注冊

  • 不常駐报咳,廣播會跟隨程序的生命周期。
  • 在 Android 的廣播機制中挖藏,動態(tài)注冊優(yōu)先級高于靜態(tài)注冊優(yōu)先級暑刃,因此在必要情況下,是需要動態(tài)注冊廣播接收者的膜眠。
    當用來注冊的 Activity 關掉后岩臣,廣播也就失效了。

BrocastReceiver 的生命周期和注意事項

  • BroadCastReceiver 的生命周期很短暫宵膨,當接收到廣播的時候創(chuàng)建架谎,當onReceive()方法結束后銷毀
  • 因為BroadCastReceiver的聲明周期很短暫,所以不要在廣播接收器中去創(chuàng)建子線程做耗時的操作辟躏,因為廣播接受者被銷毀后谷扣,這個子進程就會成為空進程,很容易被殺死
  • BroadCastReceiver是運行在主線程的捎琐,所以不能直接在BroadCastReceiver中去做耗時的操作会涎,否則就會出現(xiàn)ANR異常
    參考鏈接

動畫相關

動畫有哪幾類,各有什么特點瑞凑?
三類:補間動畫末秃、幀動畫、屬性動畫拨黔。補間動畫和Drawable動畫可統(tǒng)稱為視圖動畫蛔溃。也可以將這三類動畫都歸為屬性動畫绰沥。

補間動畫(View Animation)

在xml中定義,有縮放贺待、平移徽曲、漸變、旋轉等麸塞,可組合使用秃臣。動畫集合 AnimationSet用來存放上面四種動畫的集合

幀動畫

也叫Frame動畫,可以劃分到視圖動畫的類別哪工。專門用來一個一個的顯示Drawable的resources奥此,就像放幻燈片一樣

屬性動畫

通過改變視圖的屬性,來達到動畫的效果的動畫雁比。

  • 支持對所有View能更新的屬性的動畫(需要屬性的setXxx()和getXxx())稚虎。
  • 更改的是View實際的屬性,所以不會影響其在動畫執(zhí)行后所在位置的正常使用偎捎。
    參考鏈接

過渡動畫和MotionLayout

  • MotionLayoutConstraintLayout的子類蠢终,所以它是一種布局類型,但是它能夠為布局屬性添加動畫效果茴她,是開發(fā)者實現(xiàn)動畫效果的另一個新的選擇寻拂。
  • 它可以直接通過觸摸屏幕來控制動畫的運行進度。也就是說MotionLayout會管理你的觸摸事件通過跟蹤手指的速度丈牢,并將其與系統(tǒng)中的視圖速度相匹配祭钉。從而可以自然地在兩者之間通過觸摸滑動平穩(wěn)過渡。并且在動畫里面加入了關鍵幀的概念己沛,使得其自動生成動畫在運行時某一階段會運行到關鍵幀的狀態(tài)慌核。
  • 它具有ConstraintLayout的所有屬性。MotionLayout用來處理兩個ConstraintSet之間的切換泛粹,并在根據(jù)兩個ConstraintSet的CustomAttribute參數(shù)來自動生成切換動畫遂铡。
  • MotionLayout支持在XML中完全描述一個復雜的動畫,而不需要通過Java代碼來實現(xiàn)晶姊。

Window和WindowManager

類結構圖:


image.png

SurfaceView相關

我們知道View是通過刷新來重繪視圖,系統(tǒng)通過發(fā)出VSSYNC信號來進行屏幕的重繪伪货,刷新的時間間隔是16ms,如果我們可以在16ms以內將繪制工作完成们衙,則沒有任何問題,如果我們繪制過程邏輯很復雜碱呼,并且我們的界面更新還非常頻繁蒙挑,這時候就會造成界面的卡頓,影響用戶體驗愚臀,為此Android提供了SurfaceView來解決這一問題忆蚀。如:繪制手寫簽名

View和SurfaceView的區(qū)別:

  • 1 . View適用于主動更新的情況,而SurfaceView則適用于被動更新的情況,比如頻繁刷新界面馋袜。
  • 2 . View在主線程中對頁面進行刷新男旗,而SurfaceView則開啟一個子線程來對頁面進行刷新。
  • 3 . View在繪圖時沒有實現(xiàn)雙緩沖機制欣鳖,SurfaceView在底層機制中就實現(xiàn)了雙緩沖機制察皇。

鏈接

Android中的重要術語解釋

  • 1.ActivityManagerServices,簡稱AMS泽台,服務端對象什荣,負責系統(tǒng)中所有Activity的生命周期
  • 2.ActivityThread,App的真正入口怀酷。當開啟App之后稻爬,會調用main()開始運行,開啟消息循環(huán)隊列蜕依,這就是傳說中的UI線程或者叫主線程因篇。與ActivityManagerServices配合,一起完成Activity的管理工作
  • 3.ApplicationThread笔横,用來實現(xiàn)ActivityManagerService與ActivityThread之間的交互竞滓。在ActivityManagerService需要管理相關Application中的Activity的生命周期時,通過ApplicationThread的代理對象與ActivityThread通訊吹缔。
  • 4.ApplicationThreadProxy商佑,是ApplicationThread在服務器端的代理,負責和客戶端的ApplicationThread通訊厢塘。AMS就是通過該代理與ActivityThread進行通信的茶没。
  • 5.Instrumentation,每一個應用程序只有一個Instrumentation對象晚碾,每個Activity內都有一個對該對象的引用抓半。Instrumentation可以理解為應用進程的管家,ActivityThread要創(chuàng)建或暫停某個Activity時格嘁,都需要通過Instrumentation來進行具體的操作笛求。
  • 6.ActivityStack,Activity在AMS的棧管理糕簿,用來記錄已經啟動的Activity的先后關系探入,狀態(tài)信息等。通過ActivityStack決定是否需要啟動新的進程懂诗。
  • 7.ActivityRecord梳侨,ActivityStack的管理對象馍佑,每個Activity在AMS對應一個ActivityRecord,來記錄Activity的狀態(tài)以及其他的管理信息艇潭。其實就是服務器端的Activity對象的映像。
  • 8.TaskRecord,AMS抽象出來的一個“任務”的概念,是記錄ActivityRecord的棧,一個“Task”包含若干個ActivityRecord问窃。AMS用TaskRecord確保Activity啟動和退出的順序。如果你清楚Activity的4種launchMode胖喳,那么對這個概念應該不陌生泡躯。

其他面試題

invalidate、postInvalidate和requestLayout區(qū)別

  • invalidate在主線程中調用丽焊,postInvalidate在子線程中調用较剃,通過ViewRootImpl中的ViewRootHandler進行線程調度,切到主線程技健,最終調的也是view.invalidate()
  • invalidate() -> parent.invalidateChild() -> 層層找到parent写穴,parent.invalidateChildInParent(),直到ViewRootImpl
  • ViewRootImpl.invalidateChildInParent() -> invalidateRectOnScreen() -> scheduleTraversals() -> doTraversal() -> performTraversals() -> 根據(jù)條件去執(zhí)行performMeasure() / performLayout / performDraw
  • 也就是說任意一個子View調用invalidate雌贱,最終都會到ViewRootImpl的performTraversals
  • invalidate是在view需要重繪的時候調用啊送,requestLayout方法調用后只會執(zhí)行當前view的measure和layout,而draw不一定被執(zhí)行欣孤,只有當view的位置發(fā)生改變才會執(zhí)行draw方法

Intent 可以傳遞哪些數(shù)據(jù)類型

  • Serializable:Java提供的接口馋没,用來對數(shù)據(jù)進行序列化
  • Charsequence:Java提供的接口,實現(xiàn)了這個接口的類有:CharBuffer/String/StringBuffer/StringBuilder這個四個類
  • Parcelable:Android提供了一種新的類型:Parcel降传。本類被用作封裝數(shù)據(jù)的容器篷朵,封裝后的數(shù)據(jù)可以通過Intent或IPC傳遞。 除了基本類型以外婆排,只有實現(xiàn)了Parcelable接口的類才能被放入Parcel中声旺。
  • Bundle
  • 基礎數(shù)據(jù)類型和String/StringBuffer/StringBuilder

Bitmap和Drawable的區(qū)別是什么?

  • 可以簡單地理解為 Bitmap 儲存的是像素信息段只,Drawable 儲存的是 對 Canvas 的一系列操作腮猖。而 BitmapDrawable 儲存的是「把 Bitmap 渲染到 Canvas 上」這個操作。
  • Bitmap:存儲圖像每個像素數(shù)據(jù)的容器赞枕,是final修飾的類型澈缺,不允許被繼承
  • Drawable:一種圖像繪制工具,調用canvas進行繪制鹦赎,儲存的是對Canva的一系列操作

它們之間可以互轉嗎谍椅?理論上是不可以的,但是可以通過自身生成出對方的類型來達到互轉的效果古话。

Webview與Js交互?

Webview調用Js
需要在主線程中調用

  • 基本格式:webView.loadUrl("javascript:methodName(parameterValues)");
  • 調用Js無參無返回值函數(shù):
String call = "javascript:readyToGo()";
webView.loadUrl(call);
  • 調用Js有參無返回值函數(shù)
String call = "javascript:alertMessage(\"" + "content" + "\")";
  webView.loadUrl(call);
  • 調用Js有參有返回值函數(shù)
String call = "javascript:alertMessage(\"" + "content" + "\")";
webView.evaluateJavascript(call, new ValueCallback<String>() {
          @Override
          public void onReceiveValue(String s) {
              Log.d("findCar",s);
          }
      });

Js通過WebView調用Java代碼
從API19開始锁施,Android提供了@JavascriptInterface對象注解的方式來建立起Javascript對象和Android原生對象的綁定陪踩,提供給JavScript調用的函數(shù)必須帶有@JavascriptInterface杖们。
實際上,就是3個步驟:
1.Java被Js調用的方法上加@JavascriptInterface注解肩狂;
2.WebView注冊JavaScriptInterface摘完;
3.js調用,如window.android.show("JavaScript called~!");

Js調用Android Toast方法

  • 1.編寫Java原生方法并用使用@JavascriptInterface注解
 @JavascriptInterface
  public boolean show(String s){
      Toast.makeText(getApplication(), s, Toast.LENGTH_SHORT).show();
      return true傻谁;
  }
  • 2.注冊JavaScriptInterface
webView.addJavascriptInterface(this, "android");
addJavascriptInterface的作用是把this所代表的類映射為JavaScript中的android對象孝治。
  • 3.編寫JavaScript代碼
 function toastClick(){
      var str=window.android.show("JavaScript called~!");
      console.log(str);
  }

通過H5打開App的某個頁面?

在manifest文件中最開始啟動的activity中添加:
<activity android:name=".activitys.MainActivity">
 <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="host"
            android:pathPrefix="/pathPrefix"
            android:scheme="scheme" />
    </intent-filter>
</activity>
//注意host,pathPrefix,scheme都是自己自定義的审磁,只要與h5頁面調用的一致即可,如下所示

如果要跳轉到指定的頁面谈飒,在MainActivity的onCreate()中添加:

Intent intent = getIntent();
Uri uri = intent.getData();
if (uri != null) {
        String routeId = uri.getQueryParameter("pid");
        Intent intent0 = new Intent(MainActivity.this, ZhidingActivity.class);
        startActivity(intent0);
}
uri.getQueryParameter("pid");獲取h5頁面?zhèn)鬟f的參數(shù),如果沒有的話可以忽略
注意一點态蒂,微信上對于app的喚醒有攔截杭措,在瀏覽器中才可以起作用

鏈接

其他知識點匯總參考

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钾恢,隨后出現(xiàn)的幾起案子手素,更是在濱河造成了極大的恐慌,老刑警劉巖瘩蚪,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泉懦,死亡現(xiàn)場離奇詭異,居然都是意外死亡疹瘦,警方通過查閱死者的電腦和手機崩哩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拱礁,“玉大人琢锋,你說我怎么就攤上這事∧卦睿” “怎么了吴超?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸯乃。 經常有香客問我鲸阻,道長,這世上最難降的妖魔是什么缨睡? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任鸟悴,我火速辦了婚禮,結果婚禮上奖年,老公的妹妹穿的比我還像新娘细诸。我一直安慰自己,他們只是感情好陋守,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布震贵。 她就那樣靜靜地躺著利赋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猩系。 梳的紋絲不亂的頭發(fā)上媚送,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音寇甸,去河邊找鬼塘偎。 笑死,一個胖子當著我的面吹牛拿霉,可吹牛的內容都是我干的吟秩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼友浸,長吁一口氣:“原來是場噩夢啊……” “哼峰尝!你這毒婦竟也來了?” 一聲冷哼從身側響起收恢,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤武学,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伦意,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體火窒,經...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年驮肉,在試婚紗的時候發(fā)現(xiàn)自己被綠了熏矿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡离钝,死狀恐怖票编,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情卵渴,我是刑警寧澤慧域,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站浪读,受9級特大地震影響昔榴,放射性物質發(fā)生泄漏。R本人自食惡果不足惜碘橘,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一互订、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痘拆,春花似錦仰禽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勇边。三九已至犹撒,卻和暖如春折联,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背识颊。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工诚镰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人祥款。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓清笨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親刃跛。 傳聞我的和親對象是個殘疾皇子抠艾,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355