美團實習| 週記(三)

本週知識清單以下,ps本週的感悟很是誠懇不容錯過哦~

  • 顏色透明度計算
  • SpannableString類
  • 快速切換到主線程更新UI的三種方法
  • RecycleView的item動畫
  • 使用Rxjava實現點擊防抖動
  • Java基礎之異常機制
  • 一些小感悟

1.顏色透明度計算html

若是UI在設計圖中標註的顏色是這樣的#FF0000(10%不透明度),那就須要進行顏色透明度的計算。前端

a.顏色:java

Android中顏色值一般遵循RGB/ARGB標準,使用時一般以「#」字符開頭,以16進製表示。python

  • RGB:紅色(Red)、綠色(Green)、藍色(Blue)
  • ARGB:透明度(Alpha)、紅色(Red)、綠色(Green)、藍色(Blue)

好比#FF99CC00:FF 是透明度,99是紅色值,CC是綠色值,00是藍色值程序員

b.透明度數據庫

  • 透明度共分256階,對應0~255

好比,透明=0階,50%透明=127階,不透明=255階後端

  • 在計算機上對應16進制00~FF
  • 透明度+不透明度=100%

好比,透明度10%,也就是不透明度90%數組

c.計算步驟bash

假設,UI給出的顏色是#FFFFFF(40%透明度),計算步驟以下:併發

  • 若是給的是透明度,先將透明度轉換成不透明度,即不透明度爲60%
  • 不透明度*255,即40%*255=153
  • 將計算結果轉換成16進制,即153的16進制是99
  • 最後拼接成ARGB格式,即最終的顏色值: #99FFFFFF

爲了節約時間,這裏直接給出最終計算結果,查表就好啦!


2.SpannableString類

有時候爲了美觀和醒目,會給一個TextView中顯示的文字設置不一樣的大小或顏色等樣式,笨方法是分別設置多個Textview,聰明方法固然就是用本節介紹的富文本工具SpannableString了!

a.方法

//設置字符串指定區間內的格式
setSpan(Object what, int start, int end, int flags)
複製代碼

參數含義:

  • what : 文本格式,如前景色、下劃線、模糊、超連接等,經常使用幾個:
    • ForegroundColorSpan前景色&BackgroundColorSpan背景色
    • RelativeSizeSpan相對大小&AbsoluteSizeSpan絕對大小(單位:像素px)
    • StrikethroughSpan中劃線&UnderlineSpan下劃線
    • SuperscriptSpan上標&SubscriptSpan下標
    • StyleSpan 可設置粗體new StyleSpan(Typeface.BOLD)、斜體new StyleSpan(Typeface.ITALIC)
  • start : 須要設置格式的字符串起始下標
  • end : 須要設置格式的字符串結束下標
  • flags : 標識start和end是否被包括,符號[]表示包括,符號()表示不包括,四種屬性:
    • Spanned.SPAN_INCLUSIVE_EXCLUSIVE: [起始下標,結束下標)
    • Spanned.SPAN_EXCLUSIVE_EXCLUSIVE :(起始下標,結束下標)
    • Spanned.SPAN_INCLUSIVE_INCLUSIVE :[起始下標,結束下標]
    • Spanned.SPAN_EXCLUSIVE_INCLUSIVE: (起始下標,結束下標]

更多效果見:SpannableString 你應該知道的那些效果顯示

b.示例

還記得以前說的佔位符嗎?詳見週記(二),這裏配合佔位符給出個小例子,來一招雙劍合璧~

//string.xml
<string name="total">共 %1$d 元</string>

//設置金額的顏色爲白色,大小爲36像素
public void setTotalText(int total) {
        SpannableString spannableString = new SpannableString(getResources().getString(R.string.total, total));
        ForegroundColorSpan color = new ForegroundColorSpan(Color.parseColor("#FFFFFF"));
        spannableString.setSpan(color, 2, 2 + String.valueOf(total).length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        spannableString.setSpan(new AbsoluteSizeSpan(36), 2, 2 + String.valueOf(total).length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        mTotalText.setText(spannableString);
    }
複製代碼

3.快速切換到主線程更新UI的三種方法

a.Activity.runOnUiThread(Runnable)

把更新UI的代碼建立在Runnable中,並傳給 Activity.runOnUiThread()

  • 若是當前線程是UI線程,那麼會當即執行
  • 反之,會調用UI線程handler.post()將其放入UI線程的消息隊列中
new Thread(){
       public void run() {
           //此時在子線程
           ((MainActivity) context).runOnUiThread(new Runnable() {
 @Override
              public void run() {
                 //此時已經回到主線程,注意要強轉到主線程的MainActivity
              }
          });
       };
}.start();
複製代碼

b.View.post(Runnable)

  • 若是View已經attach到Window,直接調用UI線程的Handler發送Runnable到MessageQueue
  • 若是View還未attach到Window,將Runnable放入ViewRootImpl的RunQueue中,RunQueue會實現延遲執行Runnable任務,而且Runnable最終不會被加入到MessageQueue裏,也不會被Looper執行,而是等到ViewRootImpl的下一個performTraversals時候,把RunQueue裏的全部Runnable都拿出來並執行,接着清空RunQueue
mTextView.post(new Runnable() {
 @Override
    //可快速更新該view
    public void run() {
        mTextView.setText("xxx");
        //也能夠更新其餘view
       mIageView.setBackgroundResource(R.drawable.icon);
    }
});

複製代碼

還有View.postDelayed(Runnable, long),其中long表示延遲的毫秒數,示例以下。

//5秒倒計時跳轉到下個頁面
index=5;
mTextView.postDelayed(new Runnable() {
 @Override
            public void run() {
                mTextView.setText("" + index);
                index--;
                if (index == 0) {
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                    startActivity(intent);
                } else {
                    mTextView.postDelayed(this, 1000);
                }
            }
        }, 1000);
複製代碼

c.Handler.post(Runnable)&Handler.post(Runnable,long)有關Handler機制詳見要點提煉|開發藝術之消息機制

//假設在子線程,須要獲取主線程的Looper和Queue
new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //此時已經回到主線程
        }
    });
複製代碼

固然還能夠用AsyncTask、IntentService、HandlerThread,詳見要點提煉|開發藝術之線程,還有許多開源框架,由於這裏強調快速,因此其餘這些可自行了解~


4.RecycleView的item動畫

臨上線前一刻UI又想調整動畫,由於RecycleView自己有給item設置一些增長和刪除的動畫效果,若是要自定義就須要重寫一些方法了,以前在要點提煉|開發藝術之Animation介紹過Android的三種動畫,因此不過是大同小異,這裏給出一個自定義的增長動畫小例子理解一下。

//設置動畫開始前初始狀態
    @Override
    protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
        //設置錨點,這裏以item的中心點爲錨點放大
        holder.itemView.setPivotX(holder.itemView.getWidth() / 2);
        holder.itemView.setPivotY(holder.itemView.getHeight() / 2);
        holder.itemView.setAlpha(0);//初始狀態爲徹底透明
    }

    //設置動畫放大效果,這裏的效果是先放大1.2倍再縮小到原樣,透明度0到1
    @Override
    protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
         final DefaultAddVpaListener listener = new DefaultAddVpaListener(holder);
         ViewCompat.animate(holder.itemView)//爲當前item開啓一個動畫
                  .scaleX(1.2f)//x方向放大1.2倍
                  .scaleY(1.2f)//y方向放大1.2倍
                  .setDuration(300)//動畫持續時間300ms
                  .alpha(1)//動畫結束時爲徹底不透明
                  .setInterpolator(mInterpolator)//設置插值器
                  .setListener(new ViewPropertyAnimatorListener(){//設置動畫監聽器,包括動畫開始、結束和取消

                        @Override
                        public void onAnimationStart(View view) {
                            listener.onAnimationStart(view);
                        }

                        @Override
                        public void onAnimationEnd(View view) {
                            //上一個動畫結束後300ms再縮小item到原大小,持續時間200ms
                            ViewCompat.animate(holder.itemView)
                                    .scaleX(1f)
                                    .scaleY(1f)
                                    .setDuration(200)//動畫持續時間200ms
                                    .setInterpolator(mInterpolator)
                                    .setListener(new ViewPropertyAnimatorListener(){
                                        @Override
                                        public void onAnimationStart(View view) {
                                            listener.onAnimationStart(view);
                                        }

                                        @Override
                                        public void onAnimationEnd(View view) {
                                            listener.onAnimationEnd(view);
                                        }

                                        @Override
                                        public void onAnimationCancel(View view) {
                                            listener.onAnimationCancel(view);
                                        }
                                    })
                                    .setStartDelay(300)//延遲300ms啓動動畫
                                    .start();
                        }

                        @Override
                        public void onAnimationCancel(View view) {
                            listener.onAnimationCancel(view);
                        }
                  })
                  .start();//啓動動畫
          }
複製代碼

這裏只給了動畫實現,至於怎麼和Adapter配合到item上的全過程參考文章 RecyclerView的動畫實現(移除、添加、改變、移動)和自定義動畫的實現


5.使用Rxjava實現點擊防抖動

以前測試提了個bug,是由快速點擊Button致使的,聽聞個人表情以下,爲了周全考慮到用戶各類習慣這操做也是很瘋狂了。解決思路是給按鈕點擊添加防抖處理,在必定時間內不管點擊多少次都只調用一次事件,這裏用了Rxjava去實現,文章貼下Android RxJava 實戰系列:功能防抖

傳統辦法是進行先後兩次點擊時間間隔判斷,若是大於設定的時間間隔再執行點擊事件,代碼以下:

public abstract class OnMultiClickListener implements View.OnClickListener {

    public static final int MIN_CLICK_DELAY_TIME = 1000;
    private long lastClickTime = 0;

    @Override
    public void onClick(View v) {
        long currentTime = Calendar.getInstance().getTimeInMillis();
        if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {
            lastClickTime = currentTime;
            onMultiClick(v);
        }
    }

    public abstract void onMultiClick(View v);//具體點擊事件
}
複製代碼

6.Java基礎之異常機制

當一個程序出現錯誤時,多是如下三種錯誤:

  • 語法錯誤:如缺乏必要的標點符號、關鍵字輸入錯誤、數據類型不匹配等,在編譯器對程序進行編譯的過程當中,會把檢測到的語法錯誤以提示的方式列舉出來,故又稱爲編譯錯誤。
  • 運行時錯誤:如空指針異常,數組越界,除數爲零、數據庫鏈接失敗等,迫使程序終止,有特定的發生條件。
  • 邏輯錯誤:在語法上是有效的,可是在邏輯上是錯誤的,此類問題很差調試。

這裏說的Java異常處理機制主要是指處理運行時錯誤。

a.Throwable繼承層次結構,可見分紅兩大類Error和Exception。

  • Error(錯誤):指程序沒法恢復的異常狀況,表示運行應用程序中較嚴重的問題。
    • 發生於虛擬機自身、或者在虛擬機試圖執行應用時,如Virtual MachineError(Java虛擬機運行錯誤)、NoClassDefFoundError(類定義錯誤)。
    • 屬於不可查異常,即不強制程序員必須處理,即便不處理也不會出現語法錯誤。
  • Exception(異常):指程序有可能恢復的異常狀況,表示程序自己能夠處理的異常。又分兩大類:
    • RuntimeException(運行時異常):由程序自身的問題致使產生的異常。
      • NullPointerException(空指針異常)、IndexOutOfBoundsException(下標越界異常)。
      • 屬於不可查異常。
    • 非運行時異常:由程序外部的問題引發的異常。
      • 除了RuntimeException之外的異常,如FileNotFoundException(文件不存在異常)。
      • 屬於可查異常,即強制程序員必須進行處理,若是不進行處理則會出現語法錯誤。

附:常見的異常及其含義如圖

b.異常處理機制

(1)捕捉異常:由系統自動拋出異常

  • try 捕獲異常:用於監控,若發生異常,會拋出異常類所產生的對象並馬上結束執行,並轉向異常處理catch塊。
  • catch 處理異常:若拋出的異常對象屬於catch內所定義的異常類,則進入catch中的對應代碼段繼續運行程序,反之進入finally塊。經常使用方法:
    • e.getMessage():返回異常對象的一個簡短描述
    • e.toString():獲取異常對象的詳細信息
    • e.printStackTrace():在控制檯上打印異常對象和它的追蹤信息
  • finally 最終處理:不管是否捕獲或處理異常,finally塊裏的語句都會被執行。在如下4種特殊狀況下,finally塊纔不會被執行:
    • 在finally語句塊中發生了異常
    • 在前面的代碼中用了System.exit()退出程序
    • 程序所在的線程死亡
    • 關閉CPU
try {  

    // 可能會發生異常的程序代碼  
} catch (異常類1  異常變量) {  

    // 捕獲並處理try拋出的異常類型Type1  
} catch (異常類2  異常變量) {  

    // 捕獲並處理try拋出的異常類型Type2  
} finally {  

    // 不管是否發生異常,都將執行的語句塊  
}
複製代碼

注意:

  • 一個try、catch、finally之間不能插入其它代碼
  • catch可有多個,try和finally只能有一個
  • try後面必須至少跟着catch和finally其中的一個

(2)拋出異常:在方法中將異常對象顯性地拋出,以後異常會沿着調用層次向上拋出,交由調用它的方法來處理。

  • throws:聲明拋出的異常,位置在方法名後、異常類型前
  • throw:拋出異常,通常在方法體內部

(3)自定義異常:繼承Execption類或其子類,實現步驟以下:

  • 聲明自定義異常類並繼承Exception,可重寫方法如getMessage()
  • 在方法頭用throws聲明該方法可能拋出的異常
  • 在方法體的適當位置建立自定義異常類對象,並用throw將異常拋出
  • 調用該方法時,對可能產生的異常進行捕獲,並處理異常
//1.自定義的異常類
class MyException extends Exception { 

   String message; 

   public MyException(String ErrorMessagr) { 
      super(ErrorMessagr) ;
   }

   public String getMessage() {
      return message;
   }

}

public class Demo {

    public static void main(String[] args) {
        //4.調用方法時捕獲和處理
        try {
            test();
        } catch (MyException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
    
    //2.在方法頭聲明可能出現的異常
    public static void test() throws MyException{
        try {
            int i = 10/0;
            System.out.println("i="+i); 
        } catch (ArithmeticException e) {
            //3.在適當狀況下拋出異常
            throw new MyException("This is MyException"); 
        }
    }
}
複製代碼

推薦閱讀java程序錯誤類型及異常處理


7.一些小感悟

轉瞬一週又過去了,項目終於發版上線了,新的一期需求評審也如期而至,感受一切都在漸入佳境,收穫也沉甸甸的,愈加以爲不虛此行。(這是感悟略長的節奏啊...)

上週有幸遇上同事們每半年的績效考覈,因而旁聽了整個項目前端組的述職大會,幾個小時下來,感悟頗深。想起大一曾修過一門有關職業規劃的課程,讓我意識到大學千萬不能荒度,要有計劃地準備和積累求職的籌碼和資本,不要最後才發現簡歷一無全部,這門課深入的影響了我整個大學,我想大概此次述職大會也或多或少地影響我將來的職業生涯吧。

首先是述職的內容,分紅兩個部分,第一部分是對上期工做的回顧,包括作了什麼、有什麼價值,遇到並解決的問題、影響取得業績的障礙、上期作的好的地方,作的很差的地方以及我的成長收穫;第二部分是下期工做計劃,包括工做內容、我的成長計劃以及給團隊建議(如業務、技術、文化等)。

聽罷不由感慨身邊的牛人真的不少,有的人能保質保量的完成業務需求,而且經過必定的關鍵指標和數據來衡量和評價,好比線上報錯統計、各類異常現象數目統計、用戶訪問量等等;有的人有良好的開發流程規範,有整理和產出各種研發文檔的好習慣;有的人注重代碼質量,不斷重構代碼、優化性能、奉行『異常的考慮要大於功能的實現』;有的人在工做之餘仍不忘學習,好比深刻理解公司框架源碼、維護我的wiki並發表高質量的技術文章、積極主動進行組內知識分享、加入公司讀書協會並堅持打卡取得多本贈書獎勵......

其中一個小姐姐的有個細節顯得不同凡響,就是她提早就準備好了答辯稿並使用PPT的演講者模式,使得整個答辯很流暢自如。可能由於本身自己商科出身也有些答辯經歷,自認爲答辯前要準備好的不只是一個質量高的PPT,還須要有答辯稿配合、並進行必定的語速和儀態練習,雖然無關於開發技術,但真的會增添很多亮色,給人很好的聽覺體驗。

這陣子也在陸陸續續進行code review,由於有個梳理整個項目業務邏輯的任務,因此很認真的邊聽邊想邊作記錄,全程只有一個感覺--『不明覺厲』,你們都全神貫注的檢查每一個實現,不放過任何一個可能存在的異常,或者提出更好的解決思路。雖然指出的不少關鍵點我都有所聞,但因爲缺乏項目實踐,沒有學以至用,因此很難一會兒聯繫到某個場景,愈加感受本身任重而道遠。

最後不得再也不次誇獎一番我風格迥異的同事們,真的是個很可愛的團隊呢。嚴肅內斂、務實又靠譜和平易近人、認真又負責的兩位寶爸--組長和導師,工做嚴謹愛鑽研、生活卻不失浪漫的的話題達人超哥,熱愛運動、喜歡分水果、開朗風趣、才藝俱佳的顏值擔當田豐大哥哥,還有穩重憨厚、技術全能、個人學習榜樣楊宇大哥哥,他就是那種天天早上背單詞、早來一小時看英文技術書、GitHub各類自寫的千stars的開源框架、只看美劇來學英文、先後端通吃、腦瓜裏各類知識百寶庫、倒是和我年齡最近的那我的。有這些的小夥伴,實習都是件很開心的事啊!

相關文章
相關標籤/搜索