AsyncTask无法及时向主线程返回结果,求替代Thread.Sleep的方案
解决AsyncTask异步结果无法及时返回的问题
兄弟,你这个问题我太熟了!核心原因就是AsyncTask是异步执行的,主线程不会等待它完成后台任务就继续往下走,所以你在按钮点击事件里直接访问userPinRetrieved的时候,数据库请求可能还没结束,自然拿到的是null。用Thread.sleep()完全是饮鸩止渴——它会阻塞主线程,导致APP卡顿、无响应,甚至触发ANR(应用无响应)弹窗,绝对不能用!
下面给你两种靠谱的解决方案,先解决你当前用AsyncTask的问题,再给你推荐现代Android开发的替代方案:
一、正确使用AsyncTask的onPostExecute方法
AsyncTask设计的时候就考虑了这个问题:doInBackground在后台线程执行任务,任务完成后会自动调用运行在主线程的onPostExecute方法,你所有需要用到返回结果的逻辑(比如验证PIN、跳转页面、弹Toast)都应该放在这里,而不是主线程的点击事件里。
修改后的AsyncTask代码
public class AsyncTaskRunner extends AsyncTask<String, String, String> { // 用弱引用持有Activity,避免内存泄漏 private WeakReference<UserLogin> activityReference; private String userPinRetrieved; // 构造方法传入当前Activity public AsyncTaskRunner(UserLogin activity) { this.activityReference = new WeakReference<>(activity); } @Override protected String doInBackground(String... params) { try { // 你的数据库请求逻辑 BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = br.readLine()) != null) { JSONObject json = new JSONObject(line); Log.d("Line", line); // 注意:JSONObject的getString不会返回null,不存在的key会抛异常,所以用isNull判断 if (json.isNull("userPin")) { userPinRetrieved = "PIN NOT RECEIVED"; Log.d("userpin", userPinRetrieved); } else { userPinRetrieved = json.getString("userPin"); Log.d("userpin", userPinRetrieved); } } } catch (Exception e) { Log.v("ErrorAPP", e.toString()); userPinRetrieved = "ERROR"; } // 将结果返回给onPostExecute return userPinRetrieved; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); // 先检查Activity是否还存在,避免内存泄漏和空指针 UserLogin activity = activityReference.get(); if (activity == null || activity.isFinishing()) { return; } // 所有需要用到结果的逻辑都放在这里! String userPin = activity.userPin; String employee = activity.employee; Toast.makeText(activity, result + " " + userPin, Toast.LENGTH_LONG).show(); if (userPin.equals(result)) { Toast.makeText(activity, "Access Granted!", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(activity.getApplicationContext(), MainActivity.class); activity.startActivity(intent); Toast.makeText(activity, "Hello " + employee, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(activity, "Access Denied! Incorrect Pin", Toast.LENGTH_SHORT).show(); } } }
修改后的按钮点击事件
signIn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 创建AsyncTask时传入当前Activity的引用 AsyncTaskRunner postReq = new AsyncTaskRunner(UserLogin.this); postReq.execute("start"); // 这里不要再放任何需要用到userPinRetrieved的逻辑! } });
二、AsyncTask已被弃用,推荐现代替代方案
从Android API 30开始,AsyncTask已经被官方弃用了,推荐用更灵活、更安全的方式处理异步任务:
1. Java项目:ExecutorService + Handler
用线程池执行后台任务,再通过Handler回到主线程处理结果:
signIn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 创建单线程池执行后台任务 ExecutorService executor = Executors.newSingleThreadExecutor(); // 获取主线程的Handler Handler handler = new Handler(Looper.getMainLooper()); executor.execute(() -> { String userPinRetrieved = null; try { // 后台执行数据库请求 BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream())); String line; while ((line = br.readLine()) != null) { JSONObject json = new JSONObject(line); Log.d("Line", line); userPinRetrieved = json.isNull("userPin") ? "PIN NOT RECEIVED" : json.getString("userPin"); } } catch (Exception e) { Log.v("ErrorAPP", e.toString()); userPinRetrieved = "ERROR"; } final String result = userPinRetrieved; // 回到主线程处理结果 handler.post(() -> { String userPin = UserLogin.this.userPin; String employee = UserLogin.this.employee; Toast.makeText(UserLogin.this, result + " " + userPin, Toast.LENGTH_LONG).show(); if (userPin.equals(result)) { Toast.makeText(UserLogin.this, "Access Granted!", Toast.LENGTH_SHORT).show(); startActivity(new Intent(getApplicationContext(), MainActivity.class)); Toast.makeText(UserLogin.this, "Hello " + employee, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(UserLogin.this, "Access Denied! Incorrect Pin", Toast.LENGTH_SHORT).show(); } }); }); } });
2. Kotlin项目:Coroutines(协程)
协程是Kotlin官方推荐的异步处理方式,代码更简洁、安全:
signIn.setOnClickListener { // 用lifecycleScope绑定Activity生命周期,避免内存泄漏 lifecycleScope.launch { // 在IO线程执行后台任务 val result = withContext(Dispatchers.IO) { var userPinRetrieved: String? = null try { val br = BufferedReader(InputStreamReader(con.inputStream)) var line: String? while (br.readLine().also { line = it } != null) { val json = JSONObject(line!!) Log.d("Line", line!!) userPinRetrieved = if (json.isNull("userPin")) "PIN NOT RECEIVED" else json.getString("userPin") } } catch (e: Exception) { Log.v("ErrorAPP", e.toString()) userPinRetrieved = "ERROR" } userPinRetrieved } // 主线程处理结果 Toast.makeText(this@UserLogin, "$result $userPin", Toast.LENGTH_LONG).show() if (userPin == result) { Toast.makeText(this@UserLogin, "Access Granted!", Toast.LENGTH_SHORT).show() startActivity(Intent(applicationContext, MainActivity::class.java)) Toast.makeText(this@UserLogin, "Hello $employee", Toast.LENGTH_SHORT).show() } else { Toast.makeText(this@UserLogin, "Access Denied! Incorrect Pin", Toast.LENGTH_SHORT).show() } } }
内容的提问来源于stack exchange,提问作者AndroidBeginner2018
相关产品推荐
相关产品推荐

