騰訊面試被懟得體無完膚,Android面試題及答案

A求知若渴 2021-09-18 08:31:33 阅读数:509

android 答案
 ...
implementation 'com.squareup.okhttp3:okhttp:4.7.2'

}


# 簡單使用
本文使用的OkHttp版本為4.7.2。OkHttp的核心類主要有`OkHttpClient`,`Dispatcher`,`Call`,`Request`,`Response`,`Interceptor`,`Chain`。其中`OkHttpClient`是負責管理多個`Call`的組織者,而每個`Call`又包含一個`Request`和`Response`,並且`Call`中的回調用於提供響應結果。要完成一次網絡請求,我們需要告訴`Call`需要處理的`Request`是什麼樣的,例如它的URL是什麼,然後將`Call`交給`OkHttpClient`。`OkHttpClient`僅對本次請求做一些配置,例如指定緩存路徑,它會讓`Dispatcher`去决定何時執行`Call`。而`Dispatcher`的底層實現就是一個由OkHttp默認實現的線程池,它將最終執行`Call`中的`.run()`方法。最後的`Interceptor`和`Chain`將用於數據的攔截處理。OkHttp提供兩種方式提交網絡請求,分別是`Call.execute()`和`Call.enqueue(Callback)`,前者會阻塞線程,後者加入隊列异步執行。通過調用`response.body().string()`我們可以得到響應的body部分並以`String`形式返回,但值得注意的是`.string()`只能調用一次。
* **同步調用**
一般來說要在得到結果的第一時間修改UI,我們可能會使用`Call.execute()`和`AsyncTask`完成提交請求。但`AsyncTask`通常會導致`context`內存泄漏,因為它是非靜態嵌套類,所以不推薦使用同步調用。以下例子使用[https://reqres.in](
)測試請求:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private OkHttpClient mClient = new OkHttpClient();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.textView);
String url = "https://reqres.in/api/users/2";
OkHttpHandler okHttpHandler = new OkHttpHandler();
okHttpHandler.execute(url);
}
private class OkHttpHandler extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... params) {
Request request = new Request.Builder()
.url(params[0])
.build();
try {
Response response = mClient.newCall(request).execute();
return response.body().string();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
mTextView.setText(s);
}
}

}


* **异步調用**
拋開同步調用,使用`Call.enqueue(Callback)`和`Activity.runOnUiThread(Runnable)`的方式是提交請求的最佳方案。其中`Activity.runOnUiThread(Runnable)`方法傳入`Runnable`,這個`Runnable`將插入到UI線程的事件隊列末尾,等待執行`run()`方法。以下例子使用[https://reqres.in](
)測試請求:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private OkHttpClient mClient = new OkHttpClient();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.textView);
String url = "https://reqres.in/api/users/2";
try {
get(url);
} catch (IOException e) {
e.printStackTrace();
}
}
private void get(String url) {
Request request = new Request.Builder()
.url(url)
.build();
mClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
call.cancel();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String responseString = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(responseString);
}
});
}
});
}

}


# 使用HttpUrl
`HttpUrl`用於生成含參的URL,以下例子使用[https://resttesttest.com](
)測試請求:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

HttpUrl.Builder urlBuilder = HttpUrl.parse(“ https://httpbin.org/get”).newBuilder();
urlBuilder.addQueryParameter(“category”, “android”);
urlBuilder.addQueryParameter(“title”, “okhttp”);
String url2 = urlBuilder.build().toString();


# Header處理
* **設置請求頭**
`.header()`設置唯一的請求頭,舊值會被替換。`.addHeader()`新增請求頭,可以添加多值

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

Request request = new Request.Builder()
.url(url)
.addHeader(“Accept”,“application/json; charset=utf-8”)
.header(“Accept”,“application/json; charset=utf-8”)
.post(requestBody)
.build();


* **獲得響應頭**
`.header()`返回單值,`.headers()`返回多值的響應頭

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

String headerString=response.header(“Server”);
List<String> headerStrings=response.headers(“Vary”);

Log.i(TAG,headerString);
Iterator<String> it=headerStrings.iterator();
while (it.hasNext()) {
Log.i(TAG,it.next());
}


# Post提交String
以下例子使用[https://reqres.in](
)測試請求:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

private static final MediaType JSON = MediaType.parse(“application/json; charset=utf-8”);



  • 1.

String url = “ https://reqres.in/api/users/”;
String jsonString = “{\n” +
" “name”: “morpheus”,\n" +
" “job”: “leader”\n" +
“}”;



  • 1.

private void post(String url, final String requestString) {
RequestBody requestBody = RequestBody.create(JSON, requestString);

Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
mClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
call.cancel();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String responseString = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText(responseString);
}
});
}
});

}


# Post提交錶單

  • 1.
  • 2.
  • 3.

final String url = “ https://tieba.baidu.com/f”;



  • 1.

RequestBody requestBody = new FormBody.Builder()
.add(“ie”, “utf-8”)
.add(“kw”, “minecraft”)
.build();

Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();


# Post提交文件

  • 1.
  • 2.
  • 3.

public static final MediaType JPEG = MediaType.parse(“image/jpeg”);



  • 1.

File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM), “building.jpg”);

RequestBody requestBody = RequestBody.create(JPEG, file);

Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();


# Post提交流

  • 1.
  • 2.
  • 3.

RequestBody requestBody = new RequestBody() {
@Nullable
@Override
public MediaType contentType() {
return null;
}

@Override
public void writeTo(@NotNull BufferedSink bufferedSink) throws IOException {
bufferedSink.writeUtf8(requestString);
}

};

Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();


# 使用Gson解析response

  • 1.
  • 2.
  • 3.

String url = “ https://api.github.com/gists/c2a7c39532239ff261be”;



  • 1.

class Gist{
Map<String,GistFile> files;
}

class GistFile{
String content;
}



  • 1.

Gson gson = new Gson();
Gist gist = gson.fromJson(response.body().charStream(),Gist.class);
for(Map.Entry<String,GistFile> entry:gist.files.entrySet()){
Log.i(TAG,entry.getKey()+ " "+entry.getValue().content);
}


# 設置超時

  • 1.
  • 2.
  • 3.

OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(3, TimeUnit.SECONDS)
.build();


# 配置新client
`.newBuilder()`會返回一個配置相同的buidler

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(3, TimeUnit.SECONDS)
.build();

OkHttpClient client2 = client.newBuilder()
.connectTimeout(5, TimeUnit.SECONDS)
.build();


# 攔截器
攔截器(`Interceptor`)是OkHttp的概念,也是核心功能。OkHttp有兩種攔截器,分別是應用攔截器和網絡攔截器。攔截器的主要目的在於重寫`request`和`response`,可以在發出`request`前修改headers或body,也可以在收到`response`前修改headers或body。我們完全可以在用戶收到`reponse`前將其修改成一個完全不一樣的新`response`,這一功能使得我們可以進行後續的緩存策略修改或是使用gzip壓縮requestBody等操作。應用攔截器在用戶發出一次請求後的全過程中僅調用一次,而網絡攔截器可能因為重定向等問題多次調用,例如有一次重定向就會調用兩次。攔截器可以設置多個,並按添加順序進行攔截。下圖來自[OkHttp文檔](https://links.jianshu.com/go?to=https%3A%2F%2Fsquare.github.io%2Fokhttp%2Finterceptors%2F):
![騰訊面試被懟得體無完膚,Android面試題及答案_移動開發](//upload-images.jianshu.io/upload_images/18068581-afebe969be87b273.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp)
兩種攔截器區別如下,參考[OkHttp文檔](https://links.jianshu.com/go?to=https%3A%2F%2Fsquare.github.io%2Fokhttp%2Finterceptors%2F)原文:
> **Application interceptors**
>
> * Don’t need to worry about intermediate responses like redirects and retries.
> * Are always invoked once, even if the HTTP response is served from the cache.
> * Observe the application’s original intent. Unconcerned with OkHttp-injected headers like `If-None-Match`.
> * Permitted to short-circuit and not call `Chain.proceed()`.
> * Permitted to retry and make multiple calls to `Chain.proceed()`.
> * Can adjust `Call` timeouts using `withConnectTimeout`, `withReadTimeout`,`withWriteTimeout`.
>
> **Network Interceptors**
>
> * Able to operate on intermediate responses like redirects and retries.
> * Not invoked for cached responses that short-circuit the network.
> * Observe the data just as it will be transmitted over the network.
> * Access to the `Connection` that carries the request.
個人翻譯如下:
> **應用攔截器**
>
> * 使用時不需要考慮例如重定向、重試等中轉請求帶來的影響
> * 全過程只攔截一次,即使攔截的`response`來自緩存
> * 可處理來自Applcation(參考攔截器圖解)的本意。(例如`no-cache`)不涉及OkHttp的頭部注入例如`If-None-Match`頭部(這是在core注入的)
> * 可以不調用`Chain.proceed()`(例如`return`一個來自緩存的`response`,但不能`return null`)
### 更多Android高級工程師進階學習資料
**進階學習視頻**
![騰訊面試被懟得體無完膚,Android面試題及答案_Android_02](https://s6.51cto.com/images/20210918/1631924540271214.jpg)
附上:我們之前因為秋招收集的二十套一二線互聯網公司Android面試真題(含BAT、小米、華為、美團、滴滴)和我自己整理Android複習筆記(包含Android基礎知識點、Android擴展知識點、Android源碼解析、設計模式匯總、Gradle知識點、常見算法題匯總。)
![騰訊面試被懟得體無完膚,Android面試題及答案_Android_03](https://s7.51cto.com/images/20210918/1631924540320806.jpg)
* ##### **[CodeChina開源項目:《Android學習筆記總結+移動架構視頻+大廠面試真題+項目實戰源碼》](https://ali1024.coding.net/public/P7/Android/git)**
**裏面包含不同方向的自學編程路線、面試題集合/面經、及系列技術文章等,資源持續更新中…**
  • 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.
版权声明:本文为[A求知若渴]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918083132750P.html