图片上传成功却报NullPointerException错误(AsyncTask相关)
图片上传成功后应用触发空指针异常
我将图片上传至网站,上传操作成功完成,但应用出现致命错误。怀疑是AsyncTask执行时机过早导致的,目前已将SDK版本从30升级至32,使用的UCrop版本为2.2.5。
错误日志
FATAL EXCEPTION: main Process: com.myappname.dating, PID: 17170 java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter avatar at com.myappname.dating.ui.home.profileImageUploading.UserImageCropActivity$UpdateTaskA.<init>(Unknown Source:7) at com.myappname.dating.ui.home.profileImageUploading.UserImageCropActivity$updateAvaterp$1.onResponse(UserImageCropActivity.kt:190)
问题分析
空指针异常出现在UpdateTaskA的构造函数中:你把avatar声明为非空的String类型,但实际传入的值是null,触发了Kotlin的空安全检查。
具体原因是在updateAvaterp的onResponse回调里,你用!!强制获取response.body()!!.picurl——即使接口返回response.isSuccessful为true,response.body()或者picurl字段仍可能为null,直接强制取值就会导致传入UpdateTaskA的avatar参数为空。
另外,你使用AsyncTask.execute().get()会阻塞主线程,容易造成UI卡顿甚至ANR,这也是不推荐的写法。
解决方案
1. 处理接口返回的空值
在使用接口返回数据前先做空值判断,避免传入null到UpdateTaskA:
override fun onResponse(call: Call<ProfileStatus>, response: Response<ProfileStatus>) { if (response.isSuccessful) { val profileStatus = response.body() val avatarUrl = profileStatus?.picurl if (!avatarUrl.isNullOrEmpty()) { UpdateTaskA(this@UserImageCropActivity, avatarUrl, userResponse.id).execute() Toast.makeText(applicationContext, "Profile Upload Successfully", Toast.LENGTH_SHORT).show() finish() } else { Toast.makeText(applicationContext, "上传成功但未获取到头像URL", Toast.LENGTH_SHORT).show() uploadBtn.isClickable = true uploadBtn.setBackgroundColor(Color.parseColor("#2196f3")) } } else { Toast.makeText(applicationContext, "上传失败,接口返回异常", Toast.LENGTH_SHORT).show() uploadBtn.isClickable = true uploadBtn.setBackgroundColor(Color.parseColor("#2196f3")) } }
2. 修复UpdateTaskA的空安全
如果avatar存在为空的可能,将构造函数参数改为可空类型,并在内部处理:
class UpdateTaskA(var context: UserImageCropActivity, var avatar: String?, var id : Int) : AsyncTask<Void, Void, Boolean>() { override fun doInBackground(vararg params: Void?): Boolean { avatar?.let { val imageAvatar = CommonUtil.convertToString64(it) imageAvatar?.let { encodedAvatar -> context.mCrushDataBase!!.crushDao().updateAvatar(encodedAvatar, id) } } return true } override fun onPostExecute(bool: Boolean?) { // 可添加更新完成后的逻辑 } }
3. 替换废弃的AsyncTask(可选)
AsyncTask已被官方废弃,推荐用Coroutines执行后台任务,避免主线程阻塞:
// 在Activity中声明CoroutineScope private val scope = CoroutineScope(Dispatchers.Main) // 替换原来的AsyncTask调用 scope.launch { withContext(Dispatchers.IO) { avatar?.let { val imageAvatar = CommonUtil.convertToString64(it) imageAvatar?.let { encodedAvatar -> mCrushDataBase!!.crushDao().updateAvatar(encodedAvatar, userResponse.id) } } } Toast.makeText(applicationContext, "Profile Upload Successfully", Toast.LENGTH_SHORT).show() finish() }
4. 修复主线程阻塞问题
把getDataTask的阻塞调用改为非阻塞方式:
// 替换原来的userResponse = getDataTask(this).execute().get() scope.launch { userResponse = withContext(Dispatchers.IO) { val listOfdata = mCrushDataBase!!.crushDao().getData() listOfdata[0] } }
内容的提问来源于stack exchange,提问作者Sandeep Kumar
相关产品推荐
相关产品推荐

