第九天笔记
权限与网络请求课程预习
1. 有哪些权限,具体权限的介绍
普通权限
-
网络权限:允许设备访问网络
<uses-permission android:name="android.permission.INTERNET" />
-
获取网络的状态:如是否有网
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
读取手机状态:如
IMEI
等信息<uses-permission android:name="android.permission.READ_PHONE_STATE" />
-
获取
WiFi
的状态<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
敏感权限
-
写入
SDK
权限:文件下载、图片下载<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
读取SDK的权限:读取相册、文件
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-
拍摄照片和视频
<uses-permission android:name="android.permission.CAMERA" />
-
录音
<uses-permission android:name="android.permission.RECORD_AUDIO" />
-
拨打电话
<uses-permission android:name="android.permission.CALL_PHONE" />
-
读取手机联系人
<uses-permission android:name="android.permission.READ_CONTACTS" />
-
往手机写入联系人
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
权限与网络请求课程预习笔记
1. 权限申请方法
检查是否授权
// 检查是否授权
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
权限申请
requestPermissions(new String[]{Manifest.permission.CAMERA}, 200);
权限申请结果处理
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
// 处理权限申请结果
}
2. OkHttp
介绍
OkHttp
是 Square 公司开源的,专注于连接效率的 HTTP 客户端。OkHttp
提供了对 HTTP/2 和 SPDY 的支持,并提供了连接池、GZIP 压缩和 HTTP 响应缓存功能。
使用 OkHttp
进行同步请求
implementation("com.squareup.okhttp3:okhttp:4.12.0");
// 1. 创建 OkHttpClient
private final OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
// 2. 创建 Request
Request request = new Request.Builder()
.get()
.url("https://hotfix-service-prod.g.mi.com/quick-game/game/109")
.build();
// 3. 同步请求
Response response = okHttpClient.newCall(request).execute();
通过以上步骤可以实现 OkHttp
的同步请求,分别创建 OkHttpClient
实例和 Request
实例,然后通过 newCall
方法执行请求。
异步请求与Handler
1. 使用 OkHttp
进行异步请求
以下是使用 OkHttp
进行异步请求的步骤:
// 1. 创建 Request
Request request = new Request.Builder()
.get()
.url("https://hotfix-service-prod.g.mi.com/quick-game/game/109")
.build();
// 2. 异步请求
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.i(TAG, "网络请求失败");
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
Log.i(TAG, "网络请求成功, code " + response.code());
}
});
-
创建
Request
对象,指定请求方式和URL。 -
使用
enqueue
方法进行异步请求,并实现
Callback
接口处理请求结果。
onFailure
方法处理请求失败情况。onResponse
方法处理请求成功情况。
2. 什么是 Handler
Handler
是 Android 中的消息传递机制,主要用于线程间通信。其主要功能包括:
- 在子线程通过 Handler 将更新 UI 的操作传递给主线程,从而完成 UI 刷新。
- 在多线程应用场景中,将工作线程中需更新 UI 的操作信息传递到 UI 主线程,从而实现工作线程对 UI 的更新处理,最终实现异步消息的处理。
Handler 的主要方法
方法名称 | 说明 |
---|---|
sendMessage() 系列 |
发送普通消息、延迟消息,最终调用 queue.enqueueMessage() 方法将消息存入消息队列。 |
post() 系列 |
提交普通/延迟 Runnable,随后封装成 Message,调用 sendMessage() 方法将消息存入消息队列。 |
dispatchMessage(Message msg) |
分发消息,优先执行 msg.callback (也就是 runnable),其次调用 handleMessage() 。 |
通过这些方法,Handler 可以在不同线程之间传递消息和操作,实现异步任务的处理和 UI 更新。
Handler 示例
不在主线程中绘制UI的原因;避免不同线程混乱。
UI线程 : 主线程。
以下是一个详细的 Handler 示例,涵盖了如何在 Android 中使用 Handler 进行线程间通信,更新 UI 元素,以及处理延迟任务等。
Handler实现信息倒计时60s
1. 创建 Handler
首先,我们需要在主线程中创建一个 Handler 实例。
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
// 创建 Handler 实例,并重写 handleMessage 方法
handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
// 处理消息
switch (msg.what) {
case 1:
textView.setText("Message received: " + msg.obj);
break;
case 2:
textView.setText("Delayed message received: " + msg.obj);
break;
default:
break;
}
}
};
// 启动一个后台线程
new Thread(new Runnable() {
@Override
public void run() {
// 模拟一些耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 发送消息到主线程
Message msg = handler.obtainMessage(1, "Hello from background thread");
handler.sendMessage(msg);
// 发送延迟消息
Message delayedMsg = handler.obtainMessage(2, "This message is delayed");
handler.sendMessageDelayed(delayedMsg, 3000);
}
}).start();
}
}
2. 发送和处理消息
在上面的代码中,Handler 被用来在主线程中处理来自后台线程的消息。
handler.obtainMessage(int what, Object obj)
:创建一个消息实例。handler.sendMessage(Message msg)
:立即发送消息。handler.sendMessageDelayed(Message msg, long delayMillis)
:延迟发送消息。
3. 使用 post()
方法
除了发送消息,Handler 还可以直接执行 Runnable 对象。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
handler = new Handler(Looper.getMainLooper());
// 使用 post 方法在主线程中执行 Runnable
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("Runnable executed immediately");
}
});
// 使用 postDelayed 方法延迟执行 Runnable
handler.postDelayed(new Runnable() {
@Override
public void run() {
textView.setText("Runnable executed after delay");
}
}, 2000);
}
4. 使用 sendMessageAtTime()
方法
可以指定一个绝对时间来发送消息。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
handler = new Handler(Looper.getMainLooper());
// 发送定时消息
long uptimeMillis = SystemClock.uptimeMillis() + 5000; // 5秒后执行
Message msg = handler.obtainMessage(3, "Message at specific time");
handler.sendMessageAtTime(msg, uptimeMillis);
}
5. 使用 removeCallbacksAndMessages()
可以移除所有的回调和消息。
@Override
protected void onDestroy() {
super.onDestroy();
// 移除 Handler 中所有的回调和消息
handler.removeCallbacksAndMessages(null);
}
总结
通过 Handler
,可以实现以下功能:
- 线程间通信:从子线程发送消息到主线程。
- UI 更新:在主线程中更新 UI 元素。
- 延迟任务:延迟执行任务。
- 定时任务:在指定时间点执行任务。
- 移除任务:清除未执行的任务和消息。
这些功能使得 Handler
成为 Android
开发中处理线程和任务调度的强大工具。
Retrofit 简介及工作流程
1. 什么是 Retrofit
- Retrofit 是一种流行的网络请求框架,可以理解为 OkHttp 的增强版。
- 底层封装了 OkHttp,实际是一个 RESTful 的 HTTP 网络请求框架的封装。
- Retrofit 主要负责网络请求接口的封装,而网络请求的实际工作由 OkHttp 完成。
2. 工作流程
- App 应用程序 通过 Retrofit 进行网络请求。
- Retrofit 接口层封装请求参数、Header、URL 等信息,然后交给 OkHttp 继续完成请求工作。
- 服务端返回数据后,OkHttp 将原始数据交给 Retrofit。
- Retrofit 根据用户需求解析数据。
3. 总结
- Retrofit 简化了网络请求的接口定义和调用,增强了 OkHttp 的功能。
- 高效、简洁地处理网络请求和响应数据的解析。
通过这一流程,开发者可以更加便捷、高效地进行网络请求操作。
Retrofit网络请求: https://hotfix-service-prod.g.mi.com/quick-game/game/{id} 参数: id=109
https://hotfix-service-prod.g.mi.com/quick-game/api/auth/sendCode 参数: phone
110
室
这个图片展示了两个Retrofit网络请求的URL和参数信息。第一个请求URL包含一个ID参数,第二个请求URL包含一个phone参数。这些信息可能是用于在Android应用程序中访问一些游戏相关的服务接口。
Retrofit 示例
以下是一个详细的 Retrofit 示例,展示了如何在 Android 应用中使用 Retrofit 进行网络请求,包括接口定义、请求参数、响应解析等。
1. 添加依赖
首先,在你的 build.gradle
文件中添加 Retrofit 和 OkHttp 的依赖:
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
}
2. 创建数据模型
假设我们要请求一个用户信息接口,返回一个用户对象。首先定义用户数据模型:
public class User {
private int id;
private String name;
private String email;
// Getters and setters
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
3. 定义 API 接口
使用 Retrofit 的注解来定义 API 接口:
public interface ApiService {
@GET("users/{id}")
Call<User> getUserById(@Path("id") int id);
@POST("users")
Call<User> createUser(@Body User user);
@PUT("users/{id}")
Call<User> updateUser(@Path("id") int id, @Body User user);
@DELETE("users/{id}")
Call<Void> deleteUser(@Path("id") int id);
}
4. 创建 Retrofit 实例
在应用中创建一个 Retrofit 实例,并配置 OkHttp
和 Gson
转换器:
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
public class RetrofitClient {
private static final String BASE_URL = "https://api.example.com/";
private static Retrofit retrofit;
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
5. 使用 Retrofit 进行网络请求
在你的 Activity 或 Fragment 中调用 Retrofit 接口:
public class MainActivity extends AppCompatActivity {
private ApiService apiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Retrofit retrofit = RetrofitClient.getRetrofitInstance();
apiService = retrofit.create(ApiService.class);
getUserById(1);
createUser(new User());
updateUser(1, new User());
deleteUser(1);
}
private void getUserById(int id) {
Call<User> call = apiService.getUserById(id);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
User user = response.body();
// 处理用户对象
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
t.printStackTrace();
}
});
}
private void createUser(User user) {
user.setName("John Doe");
user.setEmail("john@example.com");
Call<User> call = apiService.createUser(user);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
User createdUser = response.body();
// 处理创建的用户对象
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
t.printStackTrace();
}
});
}
private void updateUser(int id, User user) {
user.setName("Jane Doe");
user.setEmail("jane@example.com");
Call<User> call = apiService.updateUser(id, user);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
User updatedUser = response.body();
// 处理更新的用户对象
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
t.printStackTrace();
}
});
}
private void deleteUser(int id) {
Call<Void> call = apiService.deleteUser(id);
call.enqueue(new Callback<Void>() {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
// 处理删除成功
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
t.printStackTrace();
}
});
}
}
package com.showguan.study_day09;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import com.showguan.study_day09.Bean.GameBean;
import com.showguan.study_day09.Bean.HttpBean;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class RetrofitActivity extends AppCompatActivity {
private static final String TAG = "RetrofitActivity";
private Gson mGson = new Gson();
private ApiServiceModule apiService;
private TextView tvMsg;
private Button btnSendId;
private Button btnSendPhone;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_retrofit);
tvMsg = findViewById(R.id.tv_msg);
btnSendId = findViewById(R.id.btn_send_id);
btnSendPhone = findViewById(R.id.btn_send_phone);
btnSendId.setOnClickListener(v -> sendRequestById());
btnSendPhone.setOnClickListener(v -> sendRequestByPhone("15610456605"));
}
private void sendRequestById() {
ApiServiceModule.getInstance().getGameService().queryGame("109").enqueue(new Callback<HttpBean<GameBean>>() {
@Override
public void onResponse(Call<HttpBean<GameBean>> call, Response<HttpBean<GameBean>> response) {
if (response.isSuccessful() && response.body() != null) {
Log.i(TAG, "http success: " + response.body().getMsg());
Log.i(TAG, "result: " + mGson.toJson(response.body()));
tvMsg.setText("Result (ID): " + mGson.toJson(response.body()));
}
// else {
// Log.i(TAG, "http failed: " + response.errorBody());
// tvMsg.setText("Request failed (ID)");
// }
}
@Override
public void onFailure(Call<HttpBean<GameBean>> call, Throwable t) {
Log.i(TAG, "http failure", t);
tvMsg.setText("Request failed (ID)");
}
});
}
private void sendRequestByPhone(String phone) {
// 示例:创建 RequestBody 并发送 POST 请求
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), "{\"phone\":\"" + phone + "\"}");
ApiServiceModule.getInstance().getGameService().sendCode(requestBody).enqueue(new Callback<HttpBean<String>>() {
@Override
public void onResponse(Call<HttpBean<String>> call, Response<HttpBean<String>> response) {
if (response.isSuccessful() && response.body() != null) {
Log.i(TAG, "http success: " + response.body().getMsg());
Log.i(TAG, "result: " + mGson.toJson(response.body()));
tvMsg.setText("Result (Phone): " + mGson.toJson(response.body()));
} else {
Log.i(TAG, "http failed: " + response.errorBody());
tvMsg.setText("Request failed (Phone)");
}
}
@Override
public void onFailure(Call<HttpBean<String>> call, Throwable t) {
Log.i(TAG, "http failure", t);
tvMsg.setText("Request failed (Phone)");
}
});
}
}
总结
通过以上示例,我们展示了如何使用 Retrofit 进行网络请求,并实现了 GET、POST、PUT 和 DELETE 请求。Retrofit 的优势在于简化了网络请求的接口定义和调用,并且与 OkHttp 结合使用,增强了功能和灵活性。
流程
MMKV
使用测试URL
火柴人
https://hotfix-service-prod.g.mi.com/quick-game/game/search?search=%E7%81%AB%E6%9F%B4%E4%BA%BA¤t=2
上拉刷新:
使用RecyclerView, 不改变数量, 但改变顺序
下拉加载,首先
Intent 线程通信
Eventbus 第三方库, 消息传递,线程切换, 本进程, 其中线程切换同样使用了Handler
Handler 线程切换, 在本进程中使用