为什么设置ArrayList后getter无法保留数据,在Fragment中访问返回null?
问题根因
Movie类的mStudiologos字段没有默认初始化,只要没走到下载逻辑的分支,这个字段就一直是null,后续直接调用get方法拿了就用肯定会触发空指针- 你当前只把logo路径列表存到了内存里的
Movie实例中,没有把这个字段同步写入本地数据库,后续Fragment从数据库查询出来的Movie对象根本没加载过这个字段的值,自然返回null - 现有代码的逻辑分支覆盖不全:
- 当电影已经存在于本地数据库时,
downloadCovers会被置为false,直接跳过整个下载和赋值逻辑 - 当电影的
studioUrl为空时,也跳过赋值逻辑 - 解析TMDB接口的JSON数据时如果抛出异常,会被空的catch块直接吞掉,也不会完成赋值
- 当电影已经存在于本地数据库时,
- 你现在把
movie.setStudiologos(studioFiles)写在for循环内部,虽然不影响结果,但属于冗余代码,只需要循环结束后赋值一次就行
修复步骤
- 给
Movie类的mStudiologos字段加默认初始化,从根源避免空指针:
- 给
public class Movie { // 初始化默认为空列表,永远不会返回null private ArrayList<String> mStudiologos = new ArrayList<>(); // 补上泛型,不要用裸类型 public ArrayList<String> getStudiologos() { return mStudiologos; } public void setStudiologos(ArrayList<String> studiologos) { // 判空避免传入null把默认值覆盖 if (studiologos != null) { this.mStudiologos = studiologos; } } .... }
- 调整下载逻辑的赋值位置,补全兜底逻辑:
public class MovieIdentification { private void createMovie(MovieStructure ms, Movie movie) { boolean downloadCovers = true; if (!movie.getId().equals(DbAdapterMovies.UNIDENTIFIED_ID) && !TextUtils.isEmpty(movie.getId())) downloadCovers = !MizuuApplication.getMovieAdapter().movieExists(movie.getId()); // 提前初始化列表,不管走不走下载逻辑都有实例 ArrayList<String> studioFiles = new ArrayList<>(); if (downloadCovers) { String thumb_filepath = FileUtils.getMovieThumb(mContext, movie.getId()).getAbsolutePath(); // 下载厂商logo if (!TextUtils.isEmpty(movie.getStudioUrl())) { JSONObject jObject = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/movie/" + movie.getId() + "?api_key=" + mTmdbApiKey + "&language=en-US"); try { JSONArray production_companies = jObject.getJSONArray("production_companies"); String baseUrl = "https://raw.githubusercontent.com/bronnel/resource.images.studios.coloured/master/resources/"; String fullUrl = ""; String studioFile = ""; for (int i = 0; i < production_companies.length(); i++) { studioFile = FileUtils.getMovieStudio1(mContext, production_companies.getJSONObject(i).getString("name")).getAbsolutePath(); fullUrl = baseUrl + production_companies.getJSONObject(i).getString("name").replaceAll(" ", "%20") + ".png"; studioFiles.add(studioFile); if (!MizLib.downloadFile(fullUrl, studioFile)) MizLib.downloadFile(fullUrl, studioFile); } } catch (JSONException e) { // 不要吞异常,至少打印日志方便排查 e.printStackTrace(); } } } // 不管走没走下载逻辑,都赋值一次,最少也是空列表不会为null movie.setStudiologos(studioFiles); // 必须新增这一步:把studiologos字段写入本地数据库,和其他电影字段一起持久化 MizuuApplication.getMovieAdapter().updateMovieStudiologos(movie.getId(), studioFiles); } }
- 给
DbAdapterMovies数据库操作类加对应字段和读写方法:
首先在电影表的建表语句里加studiologos TEXT类型的字段,存的时候把ArrayList用逗号拼接成字符串,读的时候再拆分转回ArrayList即可,比SharedPreferences适配性好得多
存数据参考逻辑:TextUtils.join(",", studioFiles)
读数据参考逻辑:如果读出来的字符串不为空,就用new ArrayList<>(Arrays.asList(studiologosStr.split(",")))转回列表,否则直接返回空列表
- 给
- 调整
Fragment里的取值逻辑,现在拿到的列表默认非空,不会再触发你日志里的空指针异常
- 调整
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

