安卓項目總結——基於喜馬拉雅SDK的安卓項目練習


寫在前面

本APP代碼已放在了github地址,需要的可以到這里去下載。

正文

  1. 需要導入網絡的相關依賴:

    // SDK在解析請求返回的JSON數據時用到
    api 'com.google.code.gson:gson:2.8.1'
    // SDK聯網框架使用okhttp
    api 'com.squareup.okhttp3:okhttp:3.11.0'
    // SDK聯網框架使用okhttp
    api 'com.squareup.okio:okio:1.15.0'
    // v4包
    api 'com.android.support:support-v4:28.0.0'
    
  2. 出現了604網絡請求錯誤,首先檢查是否導入了網絡權限:

        <!--連接網絡-->
        <uses-permission android:name="android.permission.INTERNET" />
        <!--用於管理監聽網絡狀態的變化-->
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <!--用於管理監聽網絡狀態的變化-->
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <!--用於管理監聽網絡狀態的變化-->
        <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
        <!--獲取電話的狀態,在打電話的時候暫停播放-->
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <!--target >=28 需要設置此權限 -->
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    

    然后再檢查自己的API版本,如果是大於27的版本(在build.grade里,如下圖)

    那么已經不再支持http請求了(即默認的請求訪問),需要切換成https請求:

            CommonRequest mXimalaya = CommonRequest.getInstanse();
            mXimalaya.setUseHttps(true);
    

    或者直接設置支持明文訪問:(在manifest.xml里)

    <application
        android:usesCleartextTraffic="true">
    

    還有另外一種設置方法,可以去百度查詢一下。

  3. 在創建MainContentAdapter時候,使用了AndroidX后,舊版的FragmentPagerAdapter的構造方法被標注過時,建議我們使用新版的:

        public MainContentAdapter(@NonNull FragmentManager fm, int behavior) {
            super(fm, behavior);
        }
    

    這里需要多傳一個參數behavior,我們點開源碼查看注釋,發現有兩種behavior:

一種是已經標注過時的,一種是新版的。我們傳入新版的:

        MainContentAdapter mainContentAdapter = new MainContentAdapter(supportFragmentManager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);

至於這二者的差別,根據百度的相關介紹,

具體的我也看不太懂,先做記錄。

  1. 在寫代碼的過程中,我們需要把邏輯層的代碼和UI層的代碼分開(解耦),這樣做一是可以讓我們的代碼思路更加清晰,二是更加安全,並且可以更好的復用代碼。

    要實現解耦,首先我我們要定義一個獲取接口來把需要的方法都寫入,再提供回調接口,並在獲取接口中提供對回調接口的注冊和釋放方法。之后我們書寫獲取接口的實現類,寫入獲取數據的邏輯代碼。我們在activty或者fragment用到的時候,直接創建一個邏輯層接口(獲取接口)的對象,並調用其對象的方法,然后注冊回調接口,並實現回調即可。當回調成功后,我們就直接更新UI就可以了。

    其實仔細想一想,在安卓開發中回調這個概念用到的很多。這樣的解釋未免還是太過抽象了,還是要在實際開發中養成這樣的習慣,不斷優化自己的代碼規范,從而加深自己的理解。

  2. 在我們寫UILoader時,我們把前兩個構造方法都改成了this的方式,如下:

        public UILoader(@NonNull Context context) {
            this(context,null);
        }
    
        public UILoader(@NonNull Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public UILoader(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
        }
    

    這樣的效果是我們可以讓入口唯一,即都調用第三個構造方法。

  3. 使用UILoader的思路整理:

    我們首先發起網絡請求,在請求前設置為加載中的UI,在請求成功和失敗后各自根據條件判斷加載哪個view(都調用callback里的方法),在主fragment中實現這幾個callback的方法,調用UILoader來更新UI,UILoader截獲請求后根據傳入的狀態來判斷顯示哪個。

  4. 隱藏導航欄,設置狀態欄顏色為透明的代碼:

    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
     getWindow().setStatusBarColor(Color.TRANSPARENT);
    
  5. Toast去掉前面的應用名稱的方法:我們可以先生成一個Toast對象,通過對這個Toast對象實例設置text再顯示就不會有應用名了,可以直接使用下面的工具類:

    /**
     * FileName: ToastUtil
     * Author: LiuGe
     * Date: 2020/7/29 18:15
     * Description: Toast工具類
     */
    public class ToastUtil {
    
        public static void showShort(Context context, CharSequence message) {
    
            Toast toast = Toast.makeText(context, null, Toast.LENGTH_SHORT);
    
            toast.setText(message);
    
            toast.show();
    
        }
    
        public static void showLong(Context context, CharSequence message) {
    
            Toast toast = Toast.makeText(context, null, Toast.LENGTH_LONG);
    
            toast.setText(message);
    
            toast.show();
    
        }
    }
    
  6. 在使用SharedPreference時,使用commit方法提交數據IDE提示考慮使用apply,於是百度了一下二者的差別:commit是同步提交,且有返回值表示是否提交成功,apply是異步提交,且無返回值。而SharedPreference是單實例,一般不會出現並發沖突,故如果對提交結果不關心建議使用apply,如果關心提交結果且需要同步提交的話可以使用commit。

  7. 在返回界面時,由於沒有更新狀態,需要在presenter層里寫一個更新UI和進度條的方法:

        private void handlePlayState(IPlayerCallback iPlayerCallback) {
            int playerStatus = mPlayerManager.getPlayerStatus();
            // 根據狀態調用接口的方法
            if (PlayerConstants.STATE_STARTED == playerStatus) {
                iPlayerCallback.onPlayStart();
            }else{
                iPlayerCallback.onPlayStop();
            }
        }
    
  8. 想要設置PopupWindow能夠點擊外部關閉的效果,可以使用如下代碼:

            // 這里要注意:設置setOutsideTouchable要先設置:setBackgroundDrawable
            // 否則點擊外部無法關閉pop
            setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
            setOutsideTouchable(true);
    

    這里需要注意,最好先設置一下setBackgroundDrawable,否則可能會出現無法關閉的Bug

  9. 實現PopupWindow的顯示后有一定透明度的思路:獲取Window對象,對其中的attributes里的alpha屬性做一個設置(alpha屬性:透明度),如下代碼:

        /**
         * 設置彈出框的透明度
         * @param alpha
         */
        public void updateBgAlpha(float alpha){
            Window window = getWindow();
            WindowManager.LayoutParams attributes = window.getAttributes();
            attributes.alpha = alpha;
            window.setAttributes(attributes);
        }
    
  10. 判空的重要性:在我們開發APP的時候,對於不確定的結果一定要判空處理,如該項目中,若用戶網速太慢,沒有正確的獲取到圖片路徑,那么就會導致程序崩潰。一定要對容易為空的內容進行一個判空處理。

  11. 隱藏鍵盤的代碼如下:

            // 隱藏鍵盤
            InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(mInputBox.getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
    

    其中的HIDE_IMPLICIT_ONLY為一個常量,是該方法的默認使用值。

  12. 在做訂閱和取消訂閱功能時,出了一個Bug:點擊訂閱后UI會更改,但實際上只更新了UI,點擊取消訂閱時還是會彈出訂閱成功,因為只更新了UI,沒有更新presenter里保存的map,需要在presenter的添加刪除方法里在更新UI前先查詢數據庫,更新里面的map:

        @Override
        public void onAddResult(final boolean isSuccess) {
            // 調用查詢方法,更新mData,確保能正確更新UI
            listSubscriptions();
            // 添加結果的回調
            BaseApplication.getHandler().post(new Runnable() {
                @Override
                public void run() {
                    for (ISubscriptionCallback callback : mCallbacks) {
                        callback.onAddResult(isSuccess);
                    }
                }
            });
        }
    

    (應該是我在跟着視頻敲的時候漏寫了。)

總結

總的來說,安卓的開發與web的開發相差還是很大的,在安卓開發中,需要考慮很多的情況,而在web中很多情況都會被瀏覽器處理掉,如沒有數據,網絡錯誤,數據為空等等這都需要開發者去處理,但在web上我一直沒有做過這方面的處理,就算做過也只是簡單的做了一個訪問錯誤界面。或許正規點的項目都會這樣搞吧。通過這次學習,大概了解了安卓開發的思路,但也讓我意識到自己對於某些基礎組件的了解還是太少了。這幾天老師的任務也下來了,要讓我們學大數據方面的內容,接下來學習什么再看吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM