<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      App開發(fā):模擬服務(wù)器數(shù)據(jù)接口 - MockApi

      為了方便app開發(fā)過程中,不受服務(wù)器接口的限制,便于客戶端功能的快速測(cè)試,可以在客戶端實(shí)現(xiàn)一個(gè)模擬服務(wù)器數(shù)據(jù)接口的MockApi模塊。本篇文章就嘗試為使用gradle的android項(xiàng)目設(shè)計(jì)實(shí)現(xiàn)MockApi。

      需求概述

      在app開發(fā)過程中,在和服務(wù)器人員協(xié)作時(shí),一般會(huì)第一時(shí)間確定數(shù)據(jù)接口的請(qǐng)求參數(shù)和返回?cái)?shù)據(jù)格式,然后服務(wù)器人員會(huì)盡快提供給客戶端可調(diào)試的假數(shù)據(jù)接口。不過有時(shí)候就算是假數(shù)據(jù)接口也來不及提供,或者是接口數(shù)據(jù)格式來回變動(dòng)——很可能是客戶端展示的原因,這個(gè)是產(chǎn)品設(shè)計(jì)決定的,總之帶來的問題就算服務(wù)器端的開發(fā)進(jìn)度會(huì)影響客戶端。

      所以,如果可以在客戶端的正常項(xiàng)目代碼中,自然地(不影響最終apk)添加一種模擬服務(wù)器數(shù)據(jù)返回的功能,這樣就可以很方便的在不依賴服務(wù)器的情況下展開客戶端的開發(fā)。而且考慮一種情況,為了測(cè)試不同網(wǎng)絡(luò)速度,網(wǎng)絡(luò)異常以及服務(wù)器錯(cuò)誤等各種“可能的真實(shí)數(shù)據(jù)請(qǐng)求的場(chǎng)景”對(duì)客戶端UI交互的影響,我們往往需要做很多手動(dòng)測(cè)試——千篇一律!如果本地有一種控制這種服務(wù)器響應(yīng)行為的能力那真是太好了。

      本文將介紹一種為客戶端項(xiàng)目增加模擬數(shù)據(jù)接口功能的方式,希望能減少一些開發(fā)中的煩惱。

      設(shè)計(jì)過程

      下面從分層設(shè)計(jì)、可開關(guān)模擬模塊、不同網(wǎng)絡(luò)請(qǐng)求結(jié)果的制造這幾個(gè)方面來闡述下模擬接口模塊的設(shè)計(jì)。
      為了表達(dá)方便,這里要實(shí)現(xiàn)的功能表示為“數(shù)據(jù)接口模擬模塊”,對(duì)應(yīng)英文為MockDataApi,或簡(jiǎn)寫為MockApi,正常的數(shù)據(jù)接口模塊定義為DataApi。

      分層思想

      說到分層設(shè)計(jì),MVC、MVP等模式一定程度上就起到了對(duì)代碼所屬功能的一個(gè)劃分。分層設(shè)計(jì)簡(jiǎn)單的目標(biāo)就是讓項(xiàng)目代碼更加清晰,各層相互獨(dú)立,好處不多說。

      移動(dòng)app的邏輯主要就是交互邏輯,然后需要和服務(wù)器溝通數(shù)據(jù)。所以最簡(jiǎn)單的情形下可以將一個(gè)功能(比如一個(gè)列表界面)的實(shí)現(xiàn)分UI層和數(shù)據(jù)訪問層。

      下面將數(shù)據(jù)訪問層表述為DataApi模塊,DataApi層會(huì)定義一系列的接口來描述不同類別的數(shù)據(jù)訪問請(qǐng)求。UI層使用這些接口來獲取數(shù)據(jù),而具體的數(shù)據(jù)訪問實(shí)現(xiàn)類就可以在不修改UI層代碼的情況下進(jìn)行替換。

      例如,有一個(gè)ITaskApi定義了方法List<Task> getTasks(),UI層一個(gè)界面展示任務(wù)列表,那么它使用ITaskApi來獲取數(shù)據(jù),而具體ITaskApi的實(shí)現(xiàn)類可以由DataApi層的一個(gè)工廠類DataApiManager來統(tǒng)一提供。

      有了上面的分層設(shè)計(jì),就可以為UI層動(dòng)態(tài)提供真實(shí)數(shù)據(jù)接口或模擬數(shù)據(jù)接口。

      模擬接口的開關(guān)

      可能大家都經(jīng)歷過在UI層代碼里臨時(shí)寫一些假數(shù)據(jù)得情況。比如任務(wù)列表界面,開發(fā)初,可以寫一個(gè)mockTaskData()方法來返回一個(gè)List<Task>。但這種代碼只能是開發(fā)階段有,最終apk不應(yīng)該存在。

      不能讓“模擬數(shù)據(jù)”的代碼到處散亂,在分層設(shè)計(jì)的方式下,可以將真實(shí)的數(shù)據(jù)接口DataApi和模擬數(shù)據(jù)接口MockDataApi分別作為兩個(gè)數(shù)據(jù)接口的實(shí)現(xiàn)模塊,這樣就可以根據(jù)項(xiàng)目的構(gòu)建類型來動(dòng)態(tài)提供不同的數(shù)據(jù)接口實(shí)現(xiàn)。

      實(shí)現(xiàn)MockDataApi的動(dòng)態(tài)提供的方法也不止一種。
      一般的java項(xiàng)目可以使用“工廠模式+反射”來動(dòng)態(tài)提供不同的接口實(shí)現(xiàn)類,再專業(yè)點(diǎn)就是依賴注入——DI框架的使用了。
      目前gradle是java的最先進(jìn)的構(gòu)建工具,它支持根據(jù)buildType來分別指定不同的代碼資源,或不同的依賴。
      可以在一個(gè)單獨(dú)的類庫(kù)module(就是maven中的項(xiàng)目)中來編寫各種MockDataApi的實(shí)現(xiàn)類,然后主app module在debug構(gòu)建時(shí)添加對(duì)它的依賴,此時(shí)數(shù)據(jù)接口的提供者DataApiManager可以向UI層返回這些mock類型的實(shí)例。

      為了讓“正常邏輯代碼”和mock相關(guān)代碼的關(guān)聯(lián)盡量少,可以提供一個(gè)MockApiManager來唯一獲取各個(gè)MockDataApi的實(shí)例。然后在debug構(gòu)建下的MockApiManager會(huì)返回提供了mock實(shí)現(xiàn)的數(shù)據(jù)接口實(shí)例,而release構(gòu)建時(shí)MockApiManager會(huì)一律返null。

      不同請(qǐng)求結(jié)果的模擬

      MockApi在多次請(qǐng)求時(shí)提供不同的網(wǎng)絡(luò)請(qǐng)求結(jié)果,如服務(wù)器錯(cuò)誤,網(wǎng)絡(luò)錯(cuò)誤,成功等,并模擬出一定的網(wǎng)絡(luò)延遲,這樣就很好的滿足了UI層代碼的各種測(cè)試需求。

      為了達(dá)到上述目標(biāo),定義一個(gè)接口IMockApiStrategy來表示對(duì)數(shù)據(jù)請(qǐng)求的響應(yīng)策略,它定義了方法onResponse(int callCount)。根據(jù)當(dāng)前請(qǐng)求的次數(shù)callCount,onResponse()會(huì)得到不同的模擬響應(yīng)結(jié)果。很明顯,可以根據(jù)測(cè)試需要提供不同的請(qǐng)求響應(yīng)策略,比如不斷返回成功請(qǐng)求,或者不斷返回錯(cuò)誤請(qǐng)求,或輪流返回成功和錯(cuò)誤等。

      關(guān)鍵代碼解析

      下面就給出各個(gè)部分的關(guān)鍵代碼,來說明以上所描述的MockDataApi模塊的實(shí)現(xiàn)。

      UI層代碼

      作為示例,界面MainActivity是一個(gè)“任務(wù)列表”的展示。任務(wù)由Task類表示:

      public class Task {
        public String name;
      }
      

      界面MainActivity使用一個(gè)TextView來顯示“加載中、任務(wù)列表、網(wǎng)絡(luò)錯(cuò)誤”等效果,并提供一個(gè)Button來點(diǎn)擊刷新數(shù)據(jù)。代碼如下:

      public class MainActivity extends Activity {
          private TextView tv_data;
          private boolean requesting = false;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              tv_data = (TextView) findViewById(R.id.tv_data);
      
              getData();
          }
      
          private void getData() {
              if (requesting) return;
              requesting = true;
      
              ITaskApi api = DataApiManager.ofTask();
              if (api != null) {
                  api.getTasks(new DataApiCallback<List<Task>>() {
                      @Override
                      public void onSuccess(List<Task> data) {
                          // 顯示數(shù)據(jù)
                          StringBuilder sb = new StringBuilder("請(qǐng)求數(shù)據(jù)成功:\n");
                          for (int i = 0; i < data.size(); i++) {
                              sb.append(data.get(i).name).append("\n");
                          }
      
                          tv_data.setText(sb.toString());
                          requesting = false;
                      }
      
                      @Override
                      public void onError(Throwable e) {
                          // 顯示錯(cuò)誤
                          tv_data.setText("錯(cuò)誤:\n" + e.getMessage());
                          requesting = false;
                      }
      
                      @Override
                      public void onStart() {
                          // 顯示loading
                          tv_data.setText("正在加載...");
                      }
                  });
              }
          }
      
          public void onRefreshClick(View view) {
              getData();
          }
      }
      

      在UI層代碼中,使用DataApiManager.ofTask()獲得數(shù)據(jù)訪問接口的實(shí)例。
      考慮到數(shù)據(jù)請(qǐng)求會(huì)是耗時(shí)的異步操作,這里每個(gè)數(shù)據(jù)接口方法接收一個(gè)DataApiCallback<T> 回調(diào)對(duì)象,T是將返回的數(shù)據(jù)類型。

      public interface DataApiCallback<T>  {
      
          void onSuccess(T data);
      
          void onError(Throwable e);
      
          void onStart();
      }
      

      接口DataApiCallback定義了數(shù)據(jù)接口請(qǐng)求數(shù)據(jù)開始和結(jié)束時(shí)的通知。

      DataApiManager

      根據(jù)分層設(shè)計(jì),UI層和數(shù)據(jù)訪問層之間的通信就是基于DataApi接口的,每個(gè)DataApi接口提供一組相關(guān)數(shù)據(jù)的獲取方法。獲取Task數(shù)據(jù)的接口就是ITaskApi:

      public interface ITaskApi {
          void getTasks(DataApiCallback<List<Task>> callback);
      }
      

      UI層通過DataApiManager來獲得各個(gè)DataApi接口的實(shí)例。也就是在這里,會(huì)根據(jù)當(dāng)前項(xiàng)目構(gòu)建是debug還是release來選擇性提供MockApi或最終的DataApi。

      public class DataApiManager {
          private static final boolean MOCK_ENABLE = BuildConfig.DEBUG;
      
          public static ITaskApi ofTask() {
              if (MOCK_ENABLE) {
                  ITaskApi api = MockApiManager.getMockApi(ITaskApi.class);
                  if (api != null) return api;
              }
      
              return new NetTaskApi();
          }
      }
      

      當(dāng)MOCK_ENABLE為true時(shí),會(huì)去MockApiManager檢索一個(gè)所需接口的mock實(shí)例,如果沒找到,會(huì)返回真實(shí)的數(shù)據(jù)接口的實(shí)現(xiàn),上面的NetTaskApi就是。倘若現(xiàn)在服務(wù)器還無法進(jìn)行聯(lián)合調(diào)試,它的實(shí)現(xiàn)就簡(jiǎn)單的返回一個(gè)服務(wù)器錯(cuò)誤:

      public class NetTaskApi implements ITaskApi {
          @Override
          public void getTasks(DataApiCallback<List<Task>> callback) {
              // 暫時(shí)沒用實(shí)際的數(shù)據(jù)接口實(shí)現(xiàn)
              callback.onError(new Exception("數(shù)據(jù)接口未實(shí)現(xiàn)"));
          }
      }
      

      MockApiManager

      DataApiManager利用MockApiManager來獲取數(shù)據(jù)接口的mock實(shí)例。這樣的好處是模擬數(shù)據(jù)接口的相關(guān)類型都被“封閉”起來,僅通過一個(gè)唯一類型來獲取已知的DataApi的一種(這里就指mock)實(shí)例。這樣為分離出mock相關(guān)代碼打下了基礎(chǔ)。

      在DataApiManager中,獲取數(shù)據(jù)接口實(shí)例時(shí)會(huì)根據(jù)開關(guān)變量MOCK_ENABLE判斷是否可以返回mock實(shí)例。僅從功能上看是滿足動(dòng)態(tài)提供MockApi的要求了。不過,為了讓最終release構(gòu)建的apk中不包含多余的mock相關(guān)的代碼,可以利用gradle提供的buildVariant。

      • buildVariant
        使用gradle來構(gòu)建項(xiàng)目時(shí),可以指定不同的buildType,默認(rèn)會(huì)有debug和release兩個(gè)“構(gòu)建類型”。此外,還可以提供productFlavors來提供不同的“產(chǎn)品類型”,如demo版,專業(yè)版等。
        每一種productFlavor和一個(gè)buildType組成一個(gè)buildVariant(構(gòu)建變種)。
        可以為每一個(gè)buildType,buildVariant,或productFlavor指定特定的代碼資源。

      這里利用buildType來為debug和release構(gòu)建分別指定不同的MockApiManager類的實(shí)現(xiàn)。

      默認(rèn)的項(xiàng)目代碼是在src/main/java/目錄下,創(chuàng)建目錄/src/debug/java/來放置只在debug構(gòu)建時(shí)編譯的代碼。在/src/release/java/目錄下放置只在release構(gòu)建時(shí)編譯的代碼。

      • debug構(gòu)建時(shí)的MockApiManager
      public class MockApiManager {
          private static final MockApiManager INSTANCE = new MockApiManager();
          private HashMap<String, BaseMockApi> mockApis;
      
          private MockApiManager() {}
      
          public static <T> T getMockApi(Class<T> dataApiClass) {
              if (dataApiClass == null) return null;
      
              String key = dataApiClass.getName();
      
              try {
                  T mock = (T) getInstance().mockApis.get(key);
                  return mock;
              } catch (Exception e) {
                  return null;
              }
          }
      
          private void initApiTable() {
              mockApis = new HashMap<>();
              mockApis.put(ITaskApi.class.getName(), new MockTaskApi());
          }
      
          private static MockApiManager getInstance() {
              if (INSTANCE.mockApis == null) {
                  synchronized (MockApiManager.class) {
                      if (INSTANCE.mockApis == null) {
                          INSTANCE.initApiTable();
                      }
                  }
              }
      
              return INSTANCE;
          }
      }
      

      靜態(tài)方法getMockApi()根據(jù)傳遞的接口類型信息從mockApis中獲取可能的mock實(shí)例,mockApis中注冊(cè)了需要mock的那些接口的實(shí)現(xiàn)類對(duì)象。

      • release構(gòu)建時(shí)的MockApiManager
      public class MockApiManager {
      
          public static <T> T getMockApi(Class<T> dataApiClass) {
              return null;
          }   
      }
      

      因?yàn)樽罱Krelease構(gòu)建時(shí)是不需要任何mock接口的,所以此時(shí)getMockApi()一律返回null。也沒有任何和提供mock接口相關(guān)的類型。

      通過為debug和release構(gòu)建提供不同的MockApiManager代碼,就徹底實(shí)現(xiàn)了MockApi代碼的動(dòng)態(tài)添加和移除。

      MockApi的實(shí)現(xiàn)

      模擬數(shù)據(jù)接口的思路非常簡(jiǎn)單:根據(jù)請(qǐng)求的次數(shù)callCount,運(yùn)行一定的策略來不斷地返回不同的響應(yīng)結(jié)果。
      響應(yīng)結(jié)果包括“網(wǎng)絡(luò)錯(cuò)誤、服務(wù)器錯(cuò)誤、成功”三種狀態(tài),而且還提供一定的網(wǎng)絡(luò)時(shí)間延遲的模擬。

      IMockApiStrategy

      接口IMockApiStrategy的作用就是抽象對(duì)請(qǐng)求返回不同響應(yīng)結(jié)果的策略,響應(yīng)結(jié)果由IMockApiStrategy.Response表示。

      public interface IMockApiStrategy {
          void onResponse(int callCount, Response out);
      
          /**
           * Mock響應(yīng)返回結(jié)果,表示響應(yīng)的狀態(tài)
           */
          class Response {
              public static final int STATE_NETWORK_ERROR = 1;
              public static final int STATE_SERVER_ERROR = 2;
              public static final int STATE_SUCCESS = 3;
      
              public int state = STATE_SUCCESS;
              public int delayMillis = 600;
          }
      }
      

      Response表示的響應(yīng)結(jié)果包含結(jié)果狀態(tài)和延遲時(shí)間。

      作為一個(gè)默認(rèn)的實(shí)現(xiàn),WheelApiStrategy類根據(jù)請(qǐng)求次數(shù),不斷返回上述的三種結(jié)果:

      public class WheelApiStrategy implements IMockApiStrategy {
      
          @Override
          public void onResponse(int callCount, Response out) {
              if (out == null) return;
      
              int step = callCount % 10;
      
              switch (step) {
                  case 0:
                  case 1:
                  case 2:
                  case 3:
                      out.state = Response.STATE_SUCCESS;
                      break;
                  case 4:
                  case 5:
                      out.state = Response.STATE_SERVER_ERROR;
                      break;
                  case 6:
                  case 7:
                      out.state = Response.STATE_SUCCESS;
                      break;
                  case 8:
                  case 9:
                      out.state = Response.STATE_NETWORK_ERROR;
                      break;
              }
      
              out.delayMillis = 700;
          }
      }
      

      方法onResponse()的參數(shù)out僅僅是為了避免多次創(chuàng)建小對(duì)象,對(duì)應(yīng)debug構(gòu)建,倒也沒太大意義。

      BaseMockApi

      針對(duì)每一個(gè)數(shù)據(jù)訪問接口,都可以提供一個(gè)mock實(shí)現(xiàn)。比如為接口ITaskApi提供MockTaskApi實(shí)現(xiàn)類。

      為了簡(jiǎn)化代碼,抽象基類BaseMockApi完成了大部分公共的邏輯。

      public abstract class BaseMockApi {
          protected int mCallCount;
          private IMockApiStrategy mStrategy;
          private Response mResponse = new Response();
      
          public Response onResponse() {
              if (mStrategy == null) {
                  mStrategy = getMockApiStrategy();
              }
      
              if (mStrategy != null) {
                  mStrategy.onResponse(mCallCount, mResponse);
                  mCallCount++;
              }
      
              return mResponse;
          }
      
          protected IMockApiStrategy getMockApiStrategy() {
              return new WheelApiStrategy();
          }
      
          protected void giveErrorResult(final DataApiCallback<?> callback, Response response) {
              Action1<Object> onNext = null;
      
              AndroidSchedulers.mainThread().createWorker().schedule(new Action0() {
                  @Override
                  public void call() {
                      callback.onStart();
                  }
              });
      
              switch (response.state) {
                  case Response.STATE_NETWORK_ERROR:
                      onNext = new Action1<Object>() {
                          @Override
                          public void call(Object o) {
                              callback.onError(new IOException("mock network error."));
                          }
                      };
      
                      break;
                  case Response.STATE_SERVER_ERROR:
                      onNext = new Action1<Object>() {
                          @Override
                          public void call(Object o) {
                              callback.onError(new IOException("mock server error."));
                          }
                      };
                      break;
              }
      
              if (onNext != null) {
                  Observable.just(10086)
                          .delay(response.delayMillis, TimeUnit.MILLISECONDS)
                          .subscribeOn(Schedulers.io())
                          .observeOn(AndroidSchedulers.mainThread())
                          .subscribe(onNext);
              }
          }
      
           public <T> void giveSuccessResult(final Func0<T> dataMethod, final DataApiCallback<T> callback, final Response response) {
              AndroidSchedulers.mainThread().createWorker().schedule(new Action0() {
                  @Override
                  public void call() {
                      Observable.create(new Observable.OnSubscribe<T>() {
                          @Override
                          public void call(Subscriber<? super T> subscriber) {
                              Log.d("MOCK", "onNext Thread = " + Thread.currentThread().getName());
                              subscriber.onNext(dataMethod.call());
                              subscriber.onCompleted();
                          }
                      }).
                      delay(response.delayMillis, TimeUnit.MILLISECONDS)
                      .subscribeOn(Schedulers.io())
                      .observeOn(AndroidSchedulers.mainThread())
                      .subscribe(new ApiSubcriber(callback));
                  }
              });
          }
      
          private static class ApiSubcriber<T> extends Subscriber<T> {
              private DataApiCallback<T> callback;
      
              public ApiSubcriber(DataApiCallback<T> callback) {
                  this.callback = callback;
              }
      
              @Override
              public void onStart() {
                  callback.onStart();
              }
      
              @Override
              public void onCompleted() {}
      
              @Override
              public void onError(Throwable e) {
                  callback.onError(e);
              }
      
              @Override
              public void onNext(T data) {
                  callback.onSuccess(data);
              }
          }
      }
      
      • onResponse()
        方法onResponse()根據(jù)“響應(yīng)策略”來針對(duì)一次請(qǐng)求返回一個(gè)“響應(yīng)結(jié)果”,默認(rèn)的策略由方法getMockApiStrategy()提供,子類可以重寫它提供其它策略。當(dāng)然策略對(duì)象本身也可以作為參數(shù)傳遞(此時(shí)此方法本身也沒多大意義了)。
        一個(gè)想法是,每一個(gè)MockApi類都只需要一個(gè)實(shí)例,這樣它的callCount就可以在程序運(yùn)行期間得到保持。此外,大多數(shù)情況下策略對(duì)象只需要一個(gè)就行了——它是無狀態(tài)的,封裝算法的一個(gè)“函數(shù)對(duì)象”,為了多態(tài),沒辦法讓它是靜態(tài)方法。

      • giveErrorResult()
        此方法用來執(zhí)行錯(cuò)誤回調(diào),此時(shí)是不需要數(shù)據(jù)的,只需要根據(jù)response來執(zhí)行一定的延遲,然后返回網(wǎng)絡(luò)錯(cuò)誤或服務(wù)器錯(cuò)誤。
        注意一定要在main線程上執(zhí)行callback的各個(gè)方法,這里算是一個(gè)約定,方便UI層直接操作一些View對(duì)象。

      • giveSuccessResult()
        此方法用來執(zhí)行成功回調(diào),此時(shí)需要提供數(shù)據(jù),并執(zhí)行response中的delayMillis延遲。
        參數(shù)dataMethod用來提供需要的假數(shù)據(jù),這里保證它的執(zhí)行在非main線程中。
        同樣,callback的方法都在main線程中執(zhí)行。

      上面BaseMockApi中的rxjava的一些代碼都非常簡(jiǎn)單,完全可以使用Thread來實(shí)現(xiàn)。

      提供MockTaskApi

      作為示例,這里為ITaskApi提供了一個(gè)mock實(shí)現(xiàn)類:

      public class MockTaskApi extends BaseMockApi implements ITaskApi {
      
          @Override
          public void getTasks(DataApiCallback<List<Task>> callback) {
              Response response = onResponse();
      
              if (response.state == Response.STATE_SUCCESS) {
                  Func0<List<Task>> mockTasks = new Func0<List<Task>>() {
                      @Override
                      public List<Task> call() {
                          // here to give some mock data, you can get it from a json file —— if there is.
                          ArrayList<Task> tasks = new ArrayList<>();
                          int start = (mCallCount - 1) * 6;
                          for (int i = start; i < start + 6; i++) {
                              Task task = new Task();
                              task.name = "Task - " + i;
      
                              tasks.add(task);
                          }
      
                          return tasks;
                      }
                  };
      
                  giveSuccessResult(mockTasks, callback, response);
              } else {
      
                  giveErrorResult(callback, response);
              }
          }
      }
      

      它的代碼幾乎不用過多解釋,使用代碼提供需要的返回?cái)?shù)據(jù)是非常簡(jiǎn)單的——就像你直接在UI層的Activity中寫一個(gè)方法來造假數(shù)據(jù)那樣。

      小結(jié)

      無論如何,經(jīng)過上面的一系列的努力,模擬數(shù)據(jù)接口的代碼已經(jīng)稍具模塊性質(zhì)了,它可以被動(dòng)態(tài)的開關(guān),不影響最終的release構(gòu)建,可以為需要測(cè)試的數(shù)據(jù)接口靈活的提供想要的mock實(shí)現(xiàn)。

      很值得一提的是,整個(gè)MockApi模塊都是建立在純java代碼上的。這樣從UI層請(qǐng)求到數(shù)據(jù)訪問方法的執(zhí)行,都最終是直接的java方法的調(diào)用,這樣可以很容易獲取調(diào)用傳遞的“請(qǐng)求參數(shù)”,這些參數(shù)都是java類。而如果mock是建立在網(wǎng)絡(luò)框架之上的,那么額外的http報(bào)文的解析是必不可少的。
      僅僅是為了測(cè)試的目的,分層設(shè)計(jì),讓數(shù)據(jù)訪問層可以在真實(shí)接口和mock接口間切換,更簡(jiǎn)單直接些。

      最后,造假數(shù)據(jù)當(dāng)然也可以是直接讀取json文件這樣的方式來完成,如果服務(wù)器開發(fā)人員有提供這樣的文件的話。

      示例源碼

      以上所述代碼可以在這里獲取到:
      https://github.com/everhad/AndroidMockApi

      如果你的項(xiàng)目里有模擬服務(wù)器接口這樣的需要,try it out!

      (本文使用Atom編寫)

      posted @ 2016-12-25 16:23  everhad  閱讀(16386)  評(píng)論(8)    收藏  舉報(bào)
      主站蜘蛛池模板: 黄色亚洲一区二区三区四区| 欧美人成精品网站播放| 国产360激情盗摄全集| 97欧美精品系列一区二区| 国产色精品久久人妻| 国产欧美另类久久久精品不卡| 精品综合一区二区三区四区| 美女一区二区三区在线观看视频| 欧美大胆老熟妇乱子伦视频| 久操热在线视频免费观看| 国产性色av高清在线观看| 久久综合伊人| 亚洲一区二区精品另类| 汾西县| 国产最新精品系列第三页| 少妇愉情理伦片丰满丰满午夜| 日韩精品一区二区三区中文无码 | 国产极品美女高潮无套| 亚洲一区二区经典在线播放| 成人亚洲欧美一区二区三区| 日韩在线视频线观看一区| 四虎影视一区二区精品| 成人资源网亚洲精品在线| 色一情一区二区三区四区| 一区二区三区无码免费看| 熟女人妻视频| 亚洲a∨无码无在线观看| 亚洲人成网站观看在线观看| 国产视频最新| 午夜福利在线观看6080| 日韩精品国产二区三区| 人妻中文字幕亚洲一区| 津市市| 国产色一区二区三区四区| 久久99精品久久久久久| 好吊妞| 国产无遮挡猛进猛出免费软件| 日韩高清不卡免费一区二区| 亚洲成av人片无码天堂下载| 97久久超碰国产精品2021| 亚洲精品岛国片在线观看|