Android中While循环内CountDownTimer未执行及TextView空指针问题
Android 定时获取GPS位置的问题解决
问题1:CountDownTimer未执行(无"in timer 2"输出)
原因
你在onCreate方法里写了while(true)死循环,而onCreate运行在Android的**主线程(UI线程)**中。主线程依赖Looper处理消息队列,CountDownTimer的onFinish、onTick等回调都是通过这个消息队列分发的。死循环会完全占用主线程,导致消息队列无法处理任何后续消息,CountDownTimer的定时任务自然永远不会触发。
解决方法
彻底移除死循环,改用Android推荐的定时任务实现方式,比如Handler.postDelayed、协程或者ScheduledExecutorService,绝对不能在主线程中使用死循环阻塞线程。
问题2:tv1.append抛出NullPointerException
原因
有两种常见触发场景:
- 布局加载顺序错误:你在调用
setContentView(R.layout.xxx)之前就执行了tv1 = findViewById(R.id.tv1),此时布局还未加载到内存中,findViewById会返回null,调用append方法就会触发空指针异常。 - 主线程被阻塞:即使
findViewById在setContentView之后执行,while(true)死循环会阻塞主线程,导致UI布局无法完成渲染,tv1的实例并未被正确初始化,最终同样引发空指针。
解决方法
- 确保
setContentView在findViewById之前执行,先加载布局再获取控件实例; - 移除阻塞主线程的死循环,让UI线程能正常处理视图渲染和消息分发。
修正后的代码示例
用Handler实现每隔1秒获取GPS位置的逻辑,同时避免主线程阻塞:
private TextView tv1; private FusedLocationProviderClient fusedLocationClient; private CancellationTokenSource cancellationTokenSource; private Handler handler = new Handler(Looper.getMainLooper()); private Runnable locationRunnable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 第一步:加载布局 setContentView(R.layout.your_layout); // 第二步:获取TextView实例 tv1 = findViewById(R.id.tv1); fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); cancellationTokenSource = new CancellationTokenSource(); // 定义定时执行的任务 locationRunnable = new Runnable() { @SuppressLint("MissingPermission") @Override public void run() { fusedLocationClient.getCurrentLocation(LocationRequest.QUALITY_HIGH_ACCURACY, cancellationTokenSource.getToken()) .addOnSuccessListener(location -> { if (location != null) { double latitude = location.getLatitude(); double longitude = location.getLongitude(); System.out.println("LOCATION ACQUIRED!!!!!!! 纬度:" + latitude + " 经度:" + longitude); tv1.append("纬度:" + latitude + " 经度:" + longitude + "\n"); } else { System.out.println("LOCATION IS NULL"); tv1.append("未获取到位置\n"); } }) .addOnFailureListener(e -> { System.out.println("LOCATION FAILED!!!!!!!!! " + e.getMessage()); tv1.append("获取位置失败:" + e.getMessage() + "\n"); }); // 每隔1秒重复执行当前任务 handler.postDelayed(this, 1000); } }; // 启动定时任务 handler.post(locationRunnable); } @Override protected void onDestroy() { super.onDestroy(); // 页面销毁时取消定时任务和令牌,避免内存泄漏 handler.removeCallbacks(locationRunnable); cancellationTokenSource.cancel(); }
额外注意事项
- 确保已在
AndroidManifest.xml中声明位置权限:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>(或ACCESS_COARSE_LOCATION),且在运行时动态申请了权限(Android 6.0及以上版本要求); - 不要在主线程中执行任何耗时操作,否则会触发ANR(应用无响应)弹窗;
- 使用
FusedLocationProviderClient时,务必在页面销毁时取消CancellationToken,避免内存泄漏。
内容的提问来源于stack exchange,提问作者SonOfEl
相关产品推荐
相关产品推荐

