Android应用开发笔记(2)

Gson使用泛型

如果你的后端统一了返回结果的话, 那么可以用Gson解析带泛型成员的Bean, 但在这个过程中遇到了一个坑, 现记录如下:

// 返回结果格式如下
public class Result<T> {
    private int code;
    private String message;
    private T data;
    // 省略getter和setter
    ...
}

原来的实现是这样的:

public static <T> Result<T> fromJson(String json, Class<T> clazz) {
    Gson gson = new Gson();
    Type type = new TypeToken<Result<T>>(){}.getType();
    return gson.fromJson(json, type);
}

但是上面的代码有问题, 在调试时发现data不会正常转化, 似乎是T失去了作用.

经查阅资料, 最后发现了原因和解决方案: https://www.jianshu.com/p/d62c2be60617

这是因为Java是泛型擦除的, 不像C++, 运行时是无法获得T的具体类型的, 所以自然就把data当成Object了. 因此, 我们只要手动把T的类型告诉Gson即可, 这里用了ParameterizedType 这个接口, 详情请看上面的文章.

private static class ParameterizedTypeImpl implements ParameterizedType {
    private final Class<?> raw;
    private final Type[] args;

    public ParameterizedTypeImpl(Class<?> raw, Type... args) {
        this.raw = raw;
        this.args = args != null ? args : new Type[0];
    }

    @NonNull
    @Override
    public Type[] getActualTypeArguments() {
        return args;
    }
    @NonNull
    @Override
    public Type getRawType() {
        return raw;
    }

    @Override
    public Type getOwnerType() {
        return null;
    }
}

public static <T> Result<T> fromJson(String json, Class<T> clazz) {
    Gson gson = new Gson();
    Type type = new ParameterizedTypeImpl(Result.class, clazz);
    return gson.fromJson(json, type);
}

这样就没有问题啦~( •̀ ω •́ )✧

org.json如何判断null

在org.json中null被视为一个独特的类型(org.json.JSONObject#NULL), 它重载了toString方法并且返回”null”, 所以直接用getString只会得到”null”. 应该调用org.json.JSONObject#isNull(String)判断是否为空

Cannot add the same observer with different lifecycles

如果Lambda表达式中不使用外部变量或方法, 那么编译器会进行单例优化, 所以重复观察时使用了同一个observer对象, 导致此异常的发生.

解决方法也很简单:

  1. 不使用Lambda表达式, 把Lambda表达式里的代码抽到内部类中
  2. Lambda表达式内使用外部的非静态变量或方法

我选择第二种

参考自: https://juejin.cn/post/6934606974239637511

Android 9.0后在应用中使用http

从Android 9开始, 谷歌为安全起见, 应用默认是无法发起http请求的, 如果需要发送http请求, 需要在清单文件里进行配置:

第一种方式:

在清单文件的application标签中添加属性android:usesCleartextTraffic="true"

第二种方式:

在res目录下创建xml目录, 然后在里面新建network_security_config.xml, 写入以下内容:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

然后再在清单文件的application标签中添加属性android:networkSecurityConfig="@xml/network_security_config"

推荐第二种方式, 但是更推荐使用https

在Room库中删除符合指定条件的行

Room的@Delete注解只能删除指定的Entity, 若想根据条件删除可以用@Query然后在里面写自定义查询语句(神奇吧

@Query("DELETE FROM user WHERE id = :id")
void deleteById(int id);

ListView#setOnItemSelectedListener(AdapterView.OnItemSelectedListener)无效

在网上搜了一圈, 这个Listener好像只在焦点改变的时候才调用, 如果想监听选项点击应该用setOnItemClickListener

这里有详细的分析: https://www.jianshu.com/p/d11f86051c20

当然了, 能用RecyclerView就更好了

TextView中的超链接无法点击

需要调用TextView#setMovementMethod(LinkMovementMethod.getInstance())

标题: Android应用开发笔记(2)
作者: QingChenW
链接: https://dawncraft.cc/2021/07/215/
本文遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 许可
禁止商用, 非商业转载请注明作者及来源!
上一篇
下一篇
隐藏