元婴期

15. 如何在 Android 中实现网络请求?如何使用 Retrofit 和 OkHttp?

RetrofitOkHttpAndroid 中广泛使用的网络请求库,提供了简化的 HTTP 请求和响应处理。

Retrofit 的使用

  • 添加依赖

    build.gradle 中添加 RetrofitOkHttp 依赖。

     implementation 'com.squareup.retrofit2:retrofit:2.9.0'
     implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
     implementation 'com.squareup.okhttp3:okhttp:4.9.1'
    
  • 定义 API 接口

     public interface ApiService {
         @GET("posts")
         Call<List<Post>> getPosts();
     }
    
  • 创建 Retrofit 实例

     Retrofit retrofit = new Retrofit.Builder()
         .baseUrl("https://jsonplaceholder.typicode.com/")
         .addConverterFactory(GsonConverterFactory.create())
         .build();
    
     ApiService apiService = retrofit.create(ApiService.class);
    

发起请求

   apiService.getPosts().enqueue(new Callback<List<Post>>() {
       @Override
       public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
           // 处理成功响应
       }

       @Override
       public void onFailure(Call<List<Post>> call, Throwable t) {
           // 处理请求失败
       }
   });

OkHttp 的使用

OkHttp 是一个底层的 HTTP 请求库,Retrofit 的网络请求是基于 OkHttp 实现的。

示例

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
    .url("https://jsonplaceholder.typicode.com/posts")
    .build();

client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // 处理请求失败
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        // 处理成功响应
    }
});

Retrofit 提供了高层次的封装,适合简化 API 调用,而 OkHttp 更灵活,可以处理复杂的网络需求。


16. 如何在 Android 中使用 Jetpack 库?Jetpack 的核心组件有哪些?

Jetpack 是一套由 Android 官方提供的库,简化了常见的 Android 开发任务。

它包含了多种工具和架构组件,帮助开发者更高效地开发稳定且可维护的应用。

Jetpack 的核心组件

  • LiveData:一个具有生命周期感知的数据持有者,能够自动更新 UI

  • ViewModel:帮助管理 UI 数据,确保数据在 Activity/Fragment 重建时保留。

  • Navigation:简化 FragmentActivity 之间的导航,提供图形化的导航控制。

  • Room:一个持久化库,提供了对 SQLite 数据库的更简洁、安全的操作。

  • WorkManager:用于管理后台任务,即使应用退出或设备重启,任务依然能够可靠地执行。

  • Data Binding:简化了 UI 和数据的绑定过程,减少了代码重复。

使用 Jetpack 的示例

// 通过 ViewModel 和 LiveData 管理 UI 数据
public class MyViewModel extends ViewModel {
    private MutableLiveData<String> liveData = new MutableLiveData<>();

    public LiveData<String> getLiveData() {
        return liveData;
    }

    public void setLiveData(String value) {
        liveData.setValue(value);
    }
}

17. 如何在 Android 中进行依赖注入?什么是 Dagger 或 Hilt?

依赖注入(DI) 是一种设计模式,允许对象的依赖通过构造函数、方法或属性注入,而不是直接在类中实例化。

DaggerHiltAndroid 中常用的依赖注入框架。

Dagger 是一个完全静态的依赖注入框架,提供了高效的依赖注入实现,它通过注解生成依赖关系的代码。

Hilt 是基于 Dagger 的依赖注入库,简化了在 Android 项目中使用依赖注入的复杂性,特别是与 Android 生命周期和 ViewModel 集成得很好。

使用 Hilt 的步骤

  • 添加依赖

    build.gradle 中添加 Hilt 依赖。

     implementation "com.google.dagger:hilt-android:2.38.1"
     kapt "com.google.dagger:hilt-android-compiler:2.38.1"
    
  • 初始化 Hilt

    Application 类上加上 @HiltAndroidApp 注解。

     @HiltAndroidApp
     public class MyApplication extends Application {
     }
    
  • 注入依赖

    ActivityFragment 中通过 @Inject 注解注入依赖:

     @AndroidEntryPoint
     public class MyActivity extends AppCompatActivity {
         @Inject
         MyRepository repository;
     }
    

Hilt 简化了 Dagger 的使用,自动处理依赖关系的生成和注入,适合 Android 开发。


18. 如何在 Android 中优化性能?有哪些常见的性能优化策略?

  • 减少主线程阻塞

    • 将耗时操作(如网络请求、数据库访问)放在后台线程中执行,避免 ANR(应用无响应)。
  • 使用 RecyclerView 代替 ListView

    • RecyclerView 更加高效,尤其是处理大数据集时,可以实现更加流畅的滚动效果。
  • 内存优化

    • 避免内存泄漏,及时释放不再使用的对象,特别是上下文引用。使用 LeakCanary 等工具检测内存泄漏。
  • 减少过度绘制

    • UI 布局设计中,减少 View 的嵌套和重叠,使用 ConstraintLayout 来优化布局层级。
  • 懒加载数据

    • 仅在需要时加载数据,避免一次性加载所有资源。通过分页加载数据提高响应速度。
  • 使用 Bitmap 优化图片加载

    • 在处理图片时,使用合适的分辨率和压缩方式,避免加载过大的图片。

19. 如何在 Android 中处理不同屏幕尺寸和分辨率的适配问题?

Android 设备有各种不同的屏幕尺寸和分辨率,因此开发者需要进行适配,以确保应用在所有设备上都能正确显示。

  • 使用 dpsp 单位

    • dp(独立像素)用于布局中的尺寸,sp(可缩放像素)用于字体大小,这两者都可以根据设备的密度进行自动缩放。
  • 使用 ConstraintLayout

    • 通过 ConstraintLayout 可以创建更加灵活、动态的布局,减少对特定屏幕尺寸的依赖。
  • 创建多套资源

    • res 目录中为不同的屏幕尺寸提供不同的布局和图像资源。例如:
      • res/layout-sw600dp/ 适用于宽度在 600dp 以上的平板设备。
      • res/drawable-hdpi/ 提供适用于高密度屏幕的图片资源。
  • 自适应布局

    • 使用 wrap_contentmatch_parent 使控件根据内容和父容器的大小自动调整,减少硬编码的宽高值。

20. 如何在 Android 中进行内存管理?如何防止内存泄漏?

Android 中的内存管理通过 Garbage Collector (GC) 自动处理,但开发者仍然需要注意避免内存泄漏和过度的内存使用。

  • 避免持有对 Context 的静态引用

    • 不要在静态变量中保存 ActivityFragment 的引用,这样会导致 GC 无法回收内存。
  • 使用 WeakReference

    • 在某些场景下(如 HandlerAsyncTask),可以使用 WeakReference 保存对象的引用,避免长时间持有导致内存泄漏。
  • 关闭资源

    • 在使用完资源后(如 Cursor、文件流等),及时关闭它们,释放占用的内存。
  • 检测内存泄漏

    • 使用 LeakCanary 等工具检测内存泄漏,帮助找到问题源头。
  • 示例

      // 使用 WeakReference 避免内存泄漏
      private static class MyHandler extends Handler {
          private final WeakReference<MainActivity> activityReference;
    
          MyHandler(MainActivity activity) {
              activityReference = new WeakReference<>(activity);
          }
    
          @Override
          public void handleMessage(Message msg) {
              MainActivity activity = activityReference.get();
              if (activity != null) {
                  // 处理消息
              }
          }
      }
    

21. 如何在 Android 中实现动态权限请求?如何处理用户的权限授权?

  • Manifest 文件中声明权限

     <uses-permission android:name="android.permission.CAMERA" />
    
  • 检查权限

    在运行时检查应用是否已获得权限。

     if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
             != PackageManager.PERMISSION_GRANTED) {
         // 请求权限
         ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE);
     }
    
  • 处理权限请求结果

    重写 onRequestPermissionsResult() 方法处理用户的授权结果。

     @Override
     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
         if (requestCode == CAMERA_REQUEST_CODE) {
             if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                 // 权限已授予
             } else {
                 // 权限被拒绝
             }
         }
     }
    

动态权限请求在运行时进行,用户可以选择允许或拒绝权限。应用应当处理用户拒绝权限的情况,并提供适当的反馈或提示。

results matching ""

    No results matching ""