第九天笔记

权限与网络请求课程预习

1. 有哪些权限,具体权限的介绍

普通权限
  1. 网络权限:允许设备访问网络

    <uses-permission android:name="android.permission.INTERNET" />
    
  2. 获取网络的状态:如是否有网

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
  3. 读取手机状态:如IMEI等信息

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    
  4. 获取WiFi的状态

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    
敏感权限
  1. 写入SDK权限:文件下载、图片下载

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  2. 读取SDK的权限:读取相册、文件

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
  3. 拍摄照片和视频

    <uses-permission android:name="android.permission.CAMERA" />
    
  4. 录音

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  5. 拨打电话

    <uses-permission android:name="android.permission.CALL_PHONE" />
    
  6. 读取手机联系人

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    
  7. 往手机写入联系人

    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    

image-20240714082851722

image-20240714092122053

image-20240714092303325

image-20240714093236053

image-20240714100133868

image-20240714100217950

image-20240714100246083

image-20240714100341236

image-20240714100419259

image-20240714100518798

image-20240714100734689

image-20240714100811212

image-20240714104045279

image-20240714104154593

image-20240714104509144

image-20240714104639085

image-20240714104727838

image-20240714104858960

image-20240714104941798

image-20240714105027138

image-20240714105219013

权限与网络请求课程预习笔记

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 元素,以及处理延迟任务等。

image-20240714134304414

image-20240714134336474

Handler实现信息倒计时60s

image-20240714134551975

image-20240714134721481

image-20240714134921627

image-20240714135358078

image-20240714135440742

image-20240714135811294

image-20240714140334583

image-20240714144029251

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,可以实现以下功能:

  1. 线程间通信:从子线程发送消息到主线程。
  2. UI 更新:在主线程中更新 UI 元素。
  3. 延迟任务:延迟执行任务。
  4. 定时任务:在指定时间点执行任务。
  5. 移除任务:清除未执行的任务和消息。

这些功能使得 Handler 成为 Android 开发中处理线程和任务调度的强大工具。

Retrofit 简介及工作流程

image-20240714144154646

image-20240714144934118

image-20240714145111639

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

image-20240714151047162

这个图片展示了两个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 实例,并配置 OkHttpGson 转换器:

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

image-20240714151109632

image-20240714155316553

image-20240714155634712

使用测试URL

火柴人
https://hotfix-service-prod.g.mi.com/quick-game/game/search?search=%E7%81%AB%E6%9F%B4%E4%BA%BA&current=2

上拉刷新

使用RecyclerView, 不改变数量, 但改变顺序

下拉加载,首先

Intent 线程通信

Eventbus 第三方库, 消息传递,线程切换, 本进程, 其中线程切换同样使用了Handler

Handler 线程切换, 在本进程中使用