92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线

首頁

HTML2.1表單標簽及屬性介紹

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

<!DOCTYPE html>

<html>

   <head>

       <meta charset="UTF-8">

       <title>表單標簽及屬性介紹</title>

   </head>

   <body>

   <!--form:表單標簽,在html頁面創建一個表單(瀏覽器上不顯示),若要提交數據到服務器則負責收集數據的標簽要放到form內 ;-->

       <!--action:(確定表單提交的路徑);-->

       <!--method提交方式:get(默認值)有內容 ,post沒有-->

       <form action="#" method="get">


           <!--input:輸入域標簽,獲取用戶輸入信息;-->

           <!--type值不同收集方式不同:hidden(隱藏字段,數據會發送到服務器但瀏覽器不顯示),text(文本框),password(密碼框),radio(單選框),checkbox(復選框),

               file(文件上傳組件),submit(提交按鈕),button(普通按鈕),reset(重置按鈕);-->

           <!--name:元素名(表單數據需提交到服務器必提供name屬性值),服務器通過屬性值獲取提交數據;-->

           <!--readonly:只讀-->

           <!--value:設置input默認值。submit和reset為按鍵上顯示數據-->

           <!--size:大小-->

           <!--maxlength:允許輸入的最大長度-->

           隱藏字段:<input type="hidden" name="id" value=""/><br/>

           用戶名:<input type="text" name="username" readonly="readonly" value="zhangsan" size="40px" maxlength="20"/><br/>

           密碼:<input type="password" name="password"/><br/>

           確認密碼:<input type="password" name="repassword"/><br/>

           性別:<input type="radio" name="sex" value="man"/>男

           <input type="radio" name="sex" value="woman"/>女<br/>

           愛好:<input type="checkbox" name="hobby" value="釣魚"/>釣魚

           <input type="checkbox" name="hobby" value="打電動"/>打電動

           <!--checked:單選或復選框默認勾選-->

           <input type="checkbox" name="hobby" value="畫畫" checked="checked"/>畫畫<br/>

           頭像:<input type="file" /><br/>

           <!--select:下拉列表標簽-->

           籍貫:<select name="province">

               <!--option:子標簽,下拉列表中的一個選項-->

               <option>---請選擇---</option>

               <!--value:發送得服務器的選項值-->

               <option value="北京">北京</option>

               <option value="上海">上海</option>

               <!--selected:勾選當前列表項-->

               <option value="廣州" selected="selected">廣州</option>

           </select><br/>

           自我介紹:

               <!--textarea:文本域-->

               <textarea>


               </textarea><br/>

           提交按鈕:<input type="submit" value="注冊"/><br/>

           普通按鈕:<input type="button" value="普通按鈕"><br/>

           重置按鈕:<input type="reset"/>

       </form>

   </body>

</html>


藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務。


醫療保健類產品設計、界面設計及交互設計靈感

博博

醫療保健類產品設計、界面設計及交互設計靈感

UI巴巴 2018-08-03 21:40:30

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

今天將從醫療保健類產品開始延展到互動和交互界面。很多醫療產品的界面有可能是一個小屏幕,也有可能是非常大的屏幕。

產品

醫療類的產品我們選擇了一些可穿戴設備的概念設計。

醫療保健類產品設計、界面設計及交互設計靈感

Kingyo設計的Sange手表

醫療保健類產品設計、界面設計及交互設計靈感

Crux Product Design 和 Chris Pearce 設計的

醫療保健類產品設計、界面設計及交互設計靈感

Amazfit

醫療保健類產品設計、界面設計及交互設計靈感

Gra?ina Bo?kut?為盲人設計的可穿戴配件

交互

我們與不同設備的交互不斷變化,將語音用戶界面引入醫療行業將徹底改變人們對護理的看法。精細設計的語音助理能夠像人一樣,更貼心。

醫療保健類產品設計、界面設計及交互設計靈感

Michal Sambora設計的Alexa助理的界面

醫療保健類產品設計、界面設計及交互設計靈感

Gleb Kuznetsov?設計的ai智能語音助理

醫療保健類產品設計、界面設計及交互設計靈感

SELECTO設計的語音助理

界面

干凈,簡潔,充滿未來感,避免錯誤的發生。

醫療保健類產品設計、界面設計及交互設計靈感
醫療保健類產品設計、界面設計及交互設計靈感
醫療保健類產品設計、界面設計及交互設計靈感
醫療保健類產品設計、界面設計及交互設計靈感
醫療保健類產品設計、界面設計及交互設計靈感
醫療保健類產品設計、界面設計及交互設計靈感


藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務

Android MVP極限封裝(一)

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

MVP架構在Android這一塊已經盛行依舊,對于一些學習能力比較強的人來說,已經能夠運用自如甚至改造優化了,對于吾等菜鳥,卻是如此的陌生,今日這篇博客,算是小弟在學習和應用上的一點總結罷了,如有不足,還請各位大神不吝指教。

MVP架構是什么就不多說了,博主主要很大家分享的是,如何設計MVP架構。

先來分析一下MVP如何使用:M-V-P三層之間,P作為中間層,負責M,V之間的數據交互的中介,將數據從M層獲取,處理之后提交到V層,換句話說,V需要持有P的實例,P層需要持有V的實例。原理很簡單,使用泛型對數據進行封裝處理: 
1.定義一個V層的空接口,主要是方便封裝:

/**
 * V層接口
 */ public interface IView { }
            
  • 1
  • 2
  • 3
  • 4
  • 5

2.定義一個P層的接口:

/**
 * 抽象為接口
 * 
 */ public interface IPresenter<V extends IView> { /**
     * 綁定視圖
     * 
     * @param view
     */ void attachView(V view); /**
     * 解除綁定(每個V記得使用完之后解綁,主要是用于防止內存泄漏問題)
     */ void dettachView();

}
            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3.封裝P基類:綁定解綁V實例

/**
 * 抽象類 統一管理View層綁定和解除綁定
 *
 * @param <V>
 */ public class BasePresenter<V extends IView, M extends IModel> implements IPresenter<V> { private WeakReference<V> weakView; protected M model;

    public V getView() { return proxyView;
    } /**
     * 用于檢查View是否為空對象
     *
     * @return */ public boolean isAttachView() { return this.weakView != null && this.weakView.get() != null;
    } @Override public void attachView(V view) { this.weakView = new WeakReference<V>(view);
    } @Override public void dettachView() { if (this.weakView != null) { this.weakView.clear(); this.weakView = null;
        }
    }
}
            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

4.M層封裝:

/**
 * M層
 */ public interface IModel { } /**
 * 登錄model
 * Created by admin on 2018/2/5.
 */ public interface ILoginModel extends IModel { void login();
} /**
 * 登錄
 * Created by admin on 2018/2/5.
 */ public class LoginModel implements ILoginModel { @Override public void login() { // TODO: 2018/2/5 發起登錄請求  }
}
            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

之后,將數據提交到activity或者fragment就行了。 
最基本的鋪墊已經做好了,接下來就該封裝View了:

/**
 * Created by admin on 2018/2/5.
 */ public abstract class MvpActivity<V extends IView, P extends BasePresenter<V>> extends AppCompatActivity implements IView { private P presenter;

    @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState);
        ...
        presenter=getPresenter();
        presenter.attachView(this);
    } protected P getPresenter() { return presenter;
    } protected void setPresenter(P presenter) { this.presenter = presenter;
    } protected V getView() { return (V) this;
    }
    ...
    @Override protected void onDestroy() {
        presenter.dettachView();
        ... super.onDestroy();
    }
}
            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

收工,MVP基礎框架搭建完成了。沒錯,就是基礎框架,但是能不能用呢,讓我們拭目以待吧。 
先來寫一個View:

public interface ILoginView extends IView { void onLoginSuccess(); void onFailed();

}
            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后是Presneter:

/**
 * Created by admin on 2018/2/5.
 */ public class LoginPresenter extends BasePresenter<ILogin, LoginModel> { public LoginPresenter() {
        model = new LoginModel();
    }

    public void login(){
        model.login(new LoginCallBack() { @Override public void onSuccess() { if(null!=(ILogin)getView()){
                    weakView.onLoginSuccess();
                }
            } @Override public void onFailure() { if(null!=(ILogin)getView()){
                    weakView.onFailure();
                }
            }
        });
    }

}
            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

最后來完成Activity的邏輯:

public class LoginActivity extends MvpActivity<ILoginView, LoginPresenter> implements ILoginView { ...
    @Override public LoginPresenter getPresenter() { return new LoginPresenter();
    } public void login(View view) {
        String name = etUserName.getText().toString();
        String pwd = etUserPwd.getText().toString();
        getPresenter().login(name, pwd);
    }

    @Override public void onLoginSuccess() {

    }

    @Override public void onFailed(){

    ...
}


    




    


藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務。


布局怎么做到不單調而有層次?來看高手的9個技巧

濤濤

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

簡單布局怎么做到不單調而有層次?看看設計師 Czékmány Zoltán 的9個技巧。

藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計  包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務

全面易懂!寫給新手的信息架構設計指南

濤濤


如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

很多產品設計師,在畫原型或者設計 UI 的時候癡迷于工具的使用,拿到需求文檔之后急于動手畫圖,忽略了信息架構設計對于產品的作用。


信息架構作為一個產品的骨架,是產品非常重要的一部分,它決定了一個產品

的布局和未來的發展方向以及用戶對一個產品的最初印象和整體體驗。毫不夸張的說,好的產品信息架構是產品成功的一半。

那么到底什么是產品的信息架構呢?該如何設計產品的信息架構?如何評判一個產品信息架構的好壞?我們接著往下看:

一、信息架構的概念

讓我們來看一個例子:

一個飯店需要有哪些設施,如果你是飯店的老板如何合理的排布這些設施,可以讓客戶感覺很舒服的用餐,這個過程就是一個信息架構的過程。他可以讓客戶對你的飯店產生好感,從而下次用餐的時候還會想到來你這里吃飯。

在排布飯店設施的過程中我們要遵循一些規范,比如用戶的習慣或者施工規范等,正是因為需要遵循這些規范,所以我們需要一個信息架構來體現這些。

比較官方的信息架構解釋是這樣的:信息架構設計是對信息進行結構、組織以及歸類的設計,好讓使用者與用戶容易使用與理解的一項藝術與科學。

簡單來說,信息架構設計就是讓用戶可以 容易地理解你的產品是怎樣的。讓他們在使用你產品的時候可以更順利更自然。就像一進入飯店就會有一種感覺,門口是等餐的地方,進去就應該吃飯,如果找洗手間一定不會往門口走,而會往深處走。這就是信息架構的好處:他讓用戶使用同類產品時更容易上手和理解,讓產品更容易被接受。

二、為何需要信息架構設計

那對于線上產品來說為什么需要合理的信息架構呢?大家來看下邊3組 app 的 tab欄截圖。你能僅僅從 tab欄就看出這款 app 是什么類型的 app,如何使用嗎?

很明顯的,第一個是一款購物類 app,第二個是一款圖片社交類的 app,第三個是微信的 tab,雖然首頁名稱是微信,但是我相信如果把名稱換成「聊天」,你還是能認出這是微信的 tab欄。

從底部標簽欄就可以大致看出產品是用來干嘛的,這就是信息架構的作用。一個合理的信息架構可以讓產品非常容易被用戶理解,可以讓用戶第一眼對產品有一個簡單的認知,指導自己可以用產品做什么事,指導產品提供什么服務。

再看一組反例:

這三組 tab欄就讓人很困惑了,看了半天你也許根本不知道這幾款 app 是做什么用的,以及如何使用。如果你讓用戶很困惑,他會分分鐘拋棄你的 app。

所以信息架構的核心目標是為用戶提供更好的體驗,獲得更高的留存率。

一款信息架構良好的產品必然遵循以下兩個標準:

  • 讓用戶打開 app 的第一秒就知道這是一款什么 app,怎么用;
  • 用戶想要使用某一功能時,能夠第一時間找到。

我們通過這兩個標準來印證下上邊3個正面案例的信息架構:

相信你能很快速的識別出這款軟件的用途和用法,這就給提升留存提供了基礎。

那么如果信息架構像架構一個飯店一樣簡單,那么信息架構為何需要設計?

因為你的實際產品功能可能有這么多:

畢竟我們不是支付寶,沒辦法把功能像豆腐塊一樣堆疊起來,我們需要一些科學的設計方法。

三、如何設計信息架構

合理的信息架構設計需要考慮5個步驟:

下面我來分步講解一下。

1. 了解用戶,場景,習慣

首先你的產品是給到用戶用,你當然要最大限度的了解你的用戶,我們先來看下一個概念:「心智模型」。

心智模型是經由經驗及學習,腦海中對某些事物發展的過程,所寫下的劇本。人類在經歷或學習某些事件之后,會對事物的發展及變化,歸納出一些結論,然后像是寫劇本一樣,把這些經驗濃縮成一本一本的劇本,等到重復或類似的事情再度發生,我們便不自覺的應用這些先前寫好的劇本,來預測事物的發展變化。心智模型是你對事物運行發展的預測。再說得清楚一點,你「希望」事物將如何發展,并不是心智模型,但你「認為」事物將如何發展,就是你的心智模型了。

假設你從沒見過 iPad,而我剛遞給你一臺并告訴你可以用它來看書。在你打開 iPad 使用它之前,你頭腦里會有一個在 iPad 上如何閱讀的模型。你會假想書在 iPad 屏幕上是怎樣的,你可以做什么事情,比如翻頁或使用書簽,以及這些事情的大致做法。即使你以前從沒有使用過 iPad,你也有一個用 iPad 看書的「心智模型」。你頭腦里的心智模型的樣式和運作方式取決于很多因素。

用戶往往帶著以往使用 APP 的一些習慣來使用產品;線下做同一件事的習慣、生活習慣、心智模型等。要考慮哪些是可以創新的,哪些是用戶習慣,要在不妨礙用戶習慣的情況下作出更能讓用戶接受的創新。

你要考慮清楚4個問題:

用戶通常用你的產品做什么?

用戶用你的產品來做什么?用來看新聞還是用來聊天?一定要考慮清楚用戶的核心流程。從核心流程中提取信息架構的基礎形式。

用戶用這類產品最關心什么?

用新聞app 時咨詢的真實性實效性,購物類app 精準搜索和售后功能,就是你的用戶關注點在哪里,這是一個很好的突破口。

用戶有哪些思維定式?

和用戶年齡身份相關的屬性,產品體驗符合相應用戶的思維模式,心智模型,用戶就會比較容易接受。

用戶用什么類似的產品?

類似的產品也會帶來一些用戶習慣,迎合這些習慣也會讓用戶快速上手接受產品。

了解了你的用戶場景和使用習慣之后你會知道如何做出符合用戶心智的,容易被接受的產品,你不需要擔心做的產品沒有差異性或者沒有競爭力,我們可以在核心流程之外做出創新點,讓用戶覺得你的產品又好用又有些不一樣。

2. 了解業務

這里的業務包括與產品接觸的內部及外部的人提出的需求,比如公司的運營,市場,銷售,BD,公司的外部合作伙伴等。

這些人的需求我們也要收集,比如運營人員想更方便的管理注冊用戶,銷售想更多的添加廣告位,市場推廣人員要求能統計不同渠道帶來產品的下載量,注冊數,活躍數,合作伙伴需要進行賬號,內容互通等,總之只要與業務有關的人的意見,盡可能的在產品設計前多收集,即使做不了,也告訴他們原因,要不然產品上線后就等著被他們吐槽吧。

3. 調研競品的信息架構

在做一款 app 時,我們面臨了和無數競品爭搶用戶的局面,這時候分析競品就非常必要,我們需要在知己知彼的前提下,做好核心流程功能,再思考如何在差異功能上做好突破。

首先我們需要把競品功能梳理成思維導圖:

其實思維導圖就是信息架構比較基礎的形式了,但是光有思維導圖沒用,我們需要對思維導圖進行分析。

我以前做過的一款人脈 app 為例,當初對比了領英、赤兔和脈脈,分析了這4款 app 的思維導圖后得出的共性和差異點:

共性就是要符合用戶使用習慣的地方,如果你調研的3-5個產品都這么做了,很可能這里是產生用戶習慣的地方,是我們需要去遵循的,這是獲得用戶好感度的基礎。

分析產品時你一定也會得出一些產品差異的地方,而這些差異就是你的產品競爭點,也是別人用你的 app 不用其他 app 的理由。比如人脈軟件都會有社交相關的功能,但是脈脈會比較注重職場招聘、直播等互聯網職場人比較關心的點,這樣對應的用戶群體就比較會吃你這套,會提升用戶的粘性。

相信你在梳理了競品的信息架構,總結了共性和差異點之后對產品的信息架構已經有一個比較清晰的認知了,在做自己產品信息架構的時候也會更胸有成竹。但是最后還有一件事我們可以做,就是對我們的要做的產品功能做卡片分類。

4. 卡片分類

卡片分類法是我們工作中常用到的一種方法,它可以在用戶側再一次印證和檢測我們的產品信息架構。

卡片分類法就是讓用戶對功能卡片進行分類,組織,并給相關功能的集合重新定義名稱的一種自下而上的整理方法。

說直白點就是準備一堆卡片,在這些卡片上寫上你所需要包含的功能名稱,然后給到用戶側,讓用戶進行分類,讓用戶進行組織,來了解用戶到底覺得這些功能應該怎么合并怎么歸類的一種方法。它可以幫助你站在用戶角度去了解用戶是怎么認定這些功能的,也可以在卡片分類法的過程中更加了解用戶是怎么想的。

卡片分類法大概的步驟和注意點是這樣的:

卡片分類法最終會產出這樣的一個樹形圖:

5. 產出信息架構

其實到這一步信息架構大概的雛形已經有了,你可以用 axure 或者類似 mindnode 的軟件把信息架構梳理出來。

接下來你要對信息架構進行重要性分級,這樣在產品開發的前期可以幫助梳理產品研發的優先級,集中精力解決用戶的最大痛點。在產出頁面時也可以更好的把控頁面元素的大小層級,位置關系等。

最后你需要注意層和度的平衡:層一般不超過5層,超過操作困難。度過多會讓用戶認知成本增加,容易找不到想找的內容。這里的度指的是同一頁面展示的信息量。


藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計  ipad界面設計  包裝設計 、 圖標定制  用戶體驗 、交互設計、 網站建設 平面設計服務


Retrofit源碼分析

seo達人

如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

1、簡介

retrofit是一個封裝okhttp請求的網絡請求庫,可以通過Rxjava適配返回信息。

2、原理分析

我們通過Retrofit.Builder建造者模式創建一個Retrofit實例對象

public static final class Builder {
    /**
      *Android線程切換的類 
      */
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
    }

    public Builder() {
      this(Platform.get());
    }

    Builder(Retrofit retrofit) {
      platform = Platform.get();
      callFactory = retrofit.callFactory;
      baseUrl = retrofit.baseUrl;

      converterFactories.addAll(retrofit.converterFactories);
      // Remove the default BuiltInConverters instance added by build().
      converterFactories.remove(0);

      callAdapterFactories.addAll(retrofit.callAdapterFactories);
      // Remove the default, platform-aware call adapter added by build().
      callAdapterFactories.remove(callAdapterFactories.size() - 1);

      callbackExecutor = retrofit.callbackExecutor;
      validateEagerly = retrofit.validateEagerly;
    }

    public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }

    public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }

    public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
      if (httpUrl == null) {
        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
      }
      return baseUrl(httpUrl);
    }

    public Builder baseUrl(HttpUrl baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }

    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      callAdapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

    public Builder callbackExecutor(Executor executor) {
      this.callbackExecutor = checkNotNull(executor, "executor == null");
      return this;
    }

    public List<CallAdapter.Factory> callAdapterFactories() {
      return this.callAdapterFactories;
    }

    public List<Converter.Factory> converterFactories() {
      return this.converterFactories;
    }

    public Builder validateEagerly(boolean validateEagerly) {
      this.validateEagerly = validateEagerly;
      return this;
    }

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories =
          new ArrayList<>(1 + this.converterFactories.size());

      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
 } 
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129

通過Retrofit.Builder中build方法創建一個Retrofit實例對象,在創建Retrofit時會判斷用戶創建OkhttpClient對象,沒有創建Retrofit會創建一個默認okhttpClient對象,然后設置Platform中的主線程線程池,設置線程池處理器交給主線程Looper對象。然后創建一個Retrofit對象。我們通過Retrofit.create創建一個接口代理類

 public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  } 
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在調用Creater方法時,通過代理類創建Service實例對象,當我們通過接口實例對象調用方法時,通過invoke方法時,通過Method創建一個ServiceMethod對象,然后把ServiceMethod存儲起來

 public ServiceMethod build() {
          callAdapter = createCallAdapter();
          responseType = callAdapter.responseType();
          if (responseType == Response.class || responseType == okhttp3.Response.class) {
            throw methodError("'"
                + Utils.getRawType(responseType).getName()
                + "' is not a valid response body type. Did you mean ResponseBody?");
          }
          responseConverter = createResponseConverter();

          for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
          }

          if (httpMethod == null) {
            throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
          }

          if (!hasBody) {
            if (isMultipart) {
              throw methodError(
                  "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
            }
            if (isFormEncoded) {
              throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
                  + "request body (e.g., @POST).");
            }
          }

          int parameterCount = parameterAnnotationsArray.length;
          parameterHandlers = new ParameterHandler<?>[parameterCount];
          for (int p = 0; p < parameterCount; p++) {
            Type parameterType = parameterTypes[p];
            if (Utils.hasUnresolvableType(parameterType)) {
              throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
                  parameterType);
            }

            Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
            if (parameterAnnotations == null) {
              throw parameterError(p, "No Retrofit annotation found.");
            }

            parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
          }

          if (relativeUrl == null && !gotUrl) {
            throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
          }
          if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
            throw methodError("Non-body HTTP method cannot contain @Body.");
          }
          if (isFormEncoded && !gotField) {
            throw methodError("Form-encoded method must contain at least one @Field.");
          }
          if (isMultipart && !gotPart) {
            throw methodError("Multipart method must contain at least one @Part.");
          }

          return new ServiceMethod<>(this);
        }

    private CallAdapter<T, R> createCallAdapter() {
            /**
             *獲取方法返回值類型
             */
          Type returnType = method.getGenericReturnType();
          if (Utils.hasUnresolvableType(returnType)) {
            throw methodError(
                "Method return type must not include a type variable or wildcard: %s", returnType);
          }
          if (returnType == void.class) {
            throw methodError("Service methods cannot return void.");
          }
          //獲取注解信息
          Annotation[] annotations = method.getAnnotations();
          try {
            //noinspection unchecked
            return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
          } catch (RuntimeException e) { // Wide exception range because factories are user code.
            throw methodError(e, "Unable to create call adapter for %s", returnType);
          }
        } 
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

在創建ServiceMethod時,獲取我們okhttp請求是否有返回值,沒有返回值拋出異常,然后獲取注解信息,然后獲取retrofit中CallAdapter.Factory,然后調用get方法,我們在通過rxjavaFactoryAdapter.create創建的就是實現CallAdapter.Factory對象,然后調用CallAdapter.Factory中respenseType方法,然后通過我們傳遞converter對數據進行序列化,可以通過gson和fastjson進行實例化對象,然后通過parseMethodAnnomation解析請求類型

 private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
          if (this.httpMethod != null) {
            throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
                this.httpMethod, httpMethod);
          }
          this.httpMethod = httpMethod;
          this.hasBody = hasBody;

          if (value.isEmpty()) {
            return;
          }

          // Get the relative URL path and existing query string, if present.
          int question = value.indexOf('?');
          if (question != -1 && question < value.length() - 1) {
            // Ensure the query string does not have any named parameters.
            String queryParams = value.substring(question + 1);
            Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
            if (queryParamMatcher.find()) {
              throw methodError("URL query string \"%s\" must not have replace block. "
                  + "For dynamic query parameters use @Query.", queryParams);
            }
          }

          this.relativeUrl = value;
          this.relativeUrlParamNames = parsePathParameters(value);
        } 
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

通過注解類型獲取到請求類型時,通過調用相關方法解析獲取到請求url,然后通過注解獲取方法中是否有注解字段,有注解信息存儲到Set集合中。然后創建一個OkhttpCall對象,通過調用serviceMethod.adapt方法做網絡請求,serviceMethod.adapt調用是callAdapter中的adapt方法,如果用戶沒有設置callAdapter模式使用的是ExecutorCallAdapterFactory中的adapt方法

 public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            if (getRawType(returnType) != Call.class) {
                return null;
            } else {
                final Type responseType = Utils.getCallResponseType(returnType);
                return new CallAdapter<Object, Call<?>>() {
                    public Type responseType() {
                        return responseType;
                    }

                    public Call<Object> adapt(Call<Object> call) {
                        return new ExecutorCallAdapterFactory.ExecutorCallbackCall(ExecutorCallAdapterFactory.this.callbackExecutor, call);
                    }
                };
            }
        } 
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在ExectorCallAdapterFactory中調用組裝的Call方法中enqueue方法調用異步網絡請求,成功后通過Platform中MainThreadExecutor切換到主線程。在調用callback中的enqueue,onResponse和onFairlure方法時實際是調用到OkhttpCall方法的onResponse方法,在OkHttpCall.enqueue中重新組建OkHttp.Call url和參數信息,然后封裝請求,請求成功后通過parseResponse解析返回信息狀態,然后把返回信息狀態成ResponseBody對象,調用ServiceMethod.toResponse解析,在toResponse中實際是我們設置ConverterFactory對象解析數據,完成后調用callBack中onSuccess方法。

 @Override public void enqueue(final Callback<T> callback) {
        checkNotNull(callback, "callback == null");

        okhttp3.Call call;
        Throwable failure;

        synchronized (this) {
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;

          call = rawCall;
          failure = creationFailure;
          if (call == null && failure == null) {
            try {
              call = rawCall = createRawCall();
            } catch (Throwable t) {
              throwIfFatal(t);
              failure = creationFailure = t;
            }
          }
        }

        if (failure != null) {
          callback.onFailure(this, failure);
          return;
        }

        if (canceled) {
          call.cancel();
        }

        call.enqueue(new okhttp3.Callback() {
          @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              callFailure(e);
              return;
            }

            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }

          @Override public void onFailure(okhttp3.Call call, IOException e) {
            callFailure(e);
          }

          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
        });
      }
藍藍設計m.skdbbs.com )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務。

如何用最簡單的點線面,解決沒靈感?

鶴鶴

點、線、面和構成手法,就像是大廈的基石一樣,看起來毫不起眼,但力量卻無比強大。

2017【百度Doodle 設計盤點】中秋節

鶴鶴

是百度專門為重大節日或紀念日設計制作的動態百度Logo

我們特此盤點了2017年的百度Doodle設計

日歷

鏈接

個人資料

藍藍設計的小編 http://m.skdbbs.com

存檔

92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线
日韩精品第一区| 久久午夜影院| 秋霞午夜在线观看| 欧美国产日韩电影| 国产精品久久久久久久第一福利| 91精品在线麻豆| 中文字幕一区二区三区视频| 日韩欧美专区在线| 国产精品夫妻激情| 香蕉久久夜色精品国产使用方法| 鬼打鬼之黄金道士1992林正英| 亚洲国产精品一区二区尤物区| 国产日产精品一区二区三区四区的观看方式| 欧洲美女少妇精品| 91在线免费播放| 在线一区二区三区四区五区| a天堂资源在线| 日韩中文字幕精品| 欧美精品在欧美一区二区少妇| 日本三级视频在线观看| 中文字幕在线观看日韩| 不卡的av中国片| 91精品久久久久久久久久久久久| av天在线观看| 成人性生交大片| 久久一区中文字幕| 欧洲性视频在线播放| 美媛馆国产精品一区二区| 中文字幕亚洲欧美在线| 国模大尺度视频一区二区| 欧美成人激情免费网| 欧美一区中文字幕| av在线播放一区二区| 欧美xxxx黑人又粗又长| 久久亚洲精品小早川怜子| 久久久久九九九| 草莓视频成人appios| 亚洲男人天堂av网| 电影av在线| 国产欧美一区二区在线播放| 欧美综合在线第二页| 久久综合伊人77777尤物| 中文字幕在线成人| 91美女片黄在线| 免费成人黄色网| 国产精品视频yy9099| 国产97在线视频| 五月天精品一区二区三区| 91久久极品少妇xxxxⅹ软件| 国产精品成人一区二区不卡| 欧美大人香蕉在线| 欧美性videos| www.欧美日韩国产在线| 久久国产一二区| 久久精品国语| 久久久久国产精品一区| 亚洲国产99精品国自产| 99精品国自产在线| 美女尤物国产一区| 日本中文字幕一区二区视频| 暖暖在线中文免费日本| 午夜精品美女自拍福到在线| 亚洲毛片av| h片视频在线观看| 1769国内精品视频在线播放| 污污网站在线观看| 91综合视频| 国产亚洲精品久久久久久牛牛| 中文字幕中文字幕一区二区| 在线视频亚洲欧美| 欧美电影《轻佻寡妇》| 午夜精品美女久久久久av福利| 成人91在线观看| 国内精品视频一区二区三区八戒| 日本在线中文字幕一区二区三区| 欧美日韩91| 国产精品久久一区主播| 欧美极品少妇xxxxx| av在线之家电影网站| 中文字幕不卡在线播放| 奇米777国产一区国产二区| 国产一区自拍视频| 99久热re在线精品视频| 国产精品区免费视频| 欧美黑人疯狂性受xxxxx野外| 国偷自产一区二区免费视频| 老司机一区二区三区| 超级碰碰不卡在线视频| 国产日韩亚洲欧美| 久久爱www久久做| 伊人国产精品| 成人两性免费视频| 99国产精品视频免费观看| 日韩影院一区| 久久婷婷国产| 亚洲香蕉在线观看| 91ph在线| 一区二区三区免费看视频| 日皮视频在线观看| 欧美噜噜久久久xxx| 天天综合精品| 久草在线资源福利站| 成人福利在线看| 精品国产成人系列| 久久久久毛片免费观看| 中文字幕日韩av综合精品| 伊人一区二区三区久久精品| 玖玖在线精品| 51国偷自产一区二区三区| av在线播放一区| 欧美精品欧美精品系列| 日韩精品大片| 国产精品久久久久久久岛一牛影视| 一本色道久久综合亚洲精品不| 精品国产亚洲一区二区三区| 国产香蕉久久精品综合网| 在线看日韩精品电影| 国产精品日韩欧美一区二区| 日韩成人一级| 毛片在线不卡| 色又黄又爽网站www久久| 92裸体在线视频网站| 国产ts人妖一区二区| 国产一区在线电影| 国产高潮在线| 成人精品毛片| 亚洲精品亚洲人成在线观看| 久久精品视频免费播放| 日本一区二区电影| 国产精品亚洲一区二区三区妖精| 国产精品免费区二区三区观看| 久久精品国产68国产精品亚洲| 性色av一区二区咪爱| 国产精品手机在线| 日本一区二区三区在线不卡| 欧美综合亚洲图片综合区| 99riav久久精品riav| 久久久久久久电影一区| 国产成人精品综合在线观看| 欧美另类高清视频在线| 国产精品全国免费观看高清| 激情成人亚洲| 日韩电影在线一区二区| av老司机免费在线| 欧美一区二区三区视频免费播放| 在线视频国产日韩| 欧美一级免费看| 四虎国产精品永久在线国在线| 国产精品yjizz视频网| jvid福利写真一区二区三区| 久久天堂电影网| 性感美女一区二区在线观看| 亚洲ab电影| 性欧美欧美巨大69| 国产91精品在线播放| 亚洲精品中文字幕有码专区| 中文字幕在线高清| 日本99精品| 精品激情国产视频| 久久精品毛片| 视频一区三区| 欧美一区二区在线免费观看| 欧美一级淫片丝袜脚交| 亚洲精品一区二区三区四区五区|