android 4.0 以上平台选择图片报错Attempted to access a cursor after it has been closed.

本文介绍了解决Android中StaleDataException异常的方法,特别是当尝试访问已关闭的Cursor时出现的问题。通过检查API版本并手动关闭Cursor来避免异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[html]  view plain copy
  1. android.database.StaleDataException: Attempted to access a cursor after it has been closed.  
  2. at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2444)  
  3. at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2472)  
  4. at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1173)  
  5. at android.os.Handler.dispatchMessage(Handler.java:99)  
  6. at android.os.Looper.loop(Looper.java:137)  
  7. at android.app.ActivityThread.main(ActivityThread.java:4424)  
  8. at java.lang.reflect.Method.invokeNative(Native Method)  
  9. at java.lang.reflect.Method.invoke(Method.java:511)  
  10. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)  
  11. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)  
  12. at dalvik.system.NativeStart.main(Native Method)  
  13. Caused by: android.database.StaleDataException: Attempted to access a cursor after it has been closed.  

选择图片后 onActivityResult中的代码如下:

[java]  view plain copy
  1. Uri uri = data.getData();  
  2.                if (uri != null)  
  3.                {  
  4.                    mFilePath = new URIUtils().getPathFromUri(uri);  
  5.                }  

解决办法如注释中的所示。 4.0以上平台会自动关闭cursor

[java]  view plain copy
  1. protected String getPath(Uri uri)  
  2.     {  
  3.         String filePath = "";  
  4.   
  5.         String[] projection = {MediaColumns.DATA };  
  6.         Cursor cursor = managedQuery(uri,  
  7.             projection,  
  8.             null,  
  9.             null,  
  10.             null);  
  11.   
  12.         if (cursor != null)  
  13.         {  
  14.             int columnIndex = cursor.getColumnIndexOrThrow(MediaColumns.DATA);  
  15.             cursor.moveToFirst();  
  16.             filePath = cursor.getString(columnIndex);  
  17.             try  
  18.             {  
  19.                 //4.0以上的版本会自动关闭 (4.0--14;; 4.0.3--15)  
  20.                 if(Integer.parseInt(Build.VERSION.SDK) < 14)  
  21.                 {  
  22.                     cursor.close();  
  23.                 }  
  24.             }catch(Exception e)  
  25.             {  
  26.                 Log.error(TAG, "error:" + e);  
  27.             }  
  28.         }  
  29.   
  30.         return filePath;  
  31.     }  
FATAL EXCEPTION: main Process: com.dosen.watchtest, PID: 24486 java.lang.RuntimeException: Unable to resume activity {com.dosen.watchtest/com.dosen.watchtest.activity.RingtonePickerActivity}: android.database.StaleDataException: Attempted to access a cursor after it has been closed. at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3698) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3741) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1699) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6747) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:449) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: android.database.StaleDataException: Attempted to access a cursor after it has been closed. at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:63) at android.database.BulkCursorToCursorAdaptor.requery(BulkCursorToCursorAdaptor.java:132) at android.database.CursorWrapper.requery(CursorWrapper.java:228) at android.app.Activity.performRestart(Activity.java:7099) at android.app.Activity.performResume(Activity.java:7125) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3673) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3741)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1699)  at android.os.Handler.dispatchMessage(Handler.j
07-19
package com.dosen.watchtest.activity; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.dosen.watchtest.R; import com.dosen.watchtest.widget.WatchListView; import java.util.ArrayList; import java.util.List; /** * Created by Daisy */ public class RingtonePickerActivity extends SecondaryActivity { private static final String TAG = "RingtonePickerActivity"; public static void start(Context context) { Intent starter = new Intent(context, RingtonePickerActivity.class); context.startActivity(starter); } private WatchListView watchListView; private RingtoneAdapter adapter; private List<RingtoneItem> ringtoneItems = new ArrayList<>(); private Ringtone currentRingtone; private int selectedPosition = -1; private Uri currentRingtoneUri; private Cursor cursor; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_ringtone_picker); currentRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE); watchListView = findViewById(R.id.ringtone_list); getSystemRingtones(); adapter = new RingtoneAdapter(this, ringtoneItems); watchListView.setAdapter(adapter); watchListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { handleRingtoneSelection(position); } }); setDefaultSelection(); } private class RingtoneAdapter extends BaseAdapter { private final Context context; private final List<RingtoneItem> items; public RingtoneAdapter(Context context, List<RingtoneItem> items) { this.context = context; this.items = items; } @Override public int getCount() { return items.size(); } @Override public Object getItem(int position) { return items.get(position); } @Override public long getItemId(int position) { return position; } class ViewHolder { TextView tvName; ImageView ivSelected; } @Override public View getView(int position, View view, ViewGroup viewGroup) { ViewHolder holder; if (view == null) { view = LayoutInflater.from(context).inflate(R.layout.ringtone_list_item, viewGroup, false); holder = new ViewHolder(); holder.tvName = view.findViewById(R.id.tv_ringtone_name); holder.ivSelected = view.findViewById(R.id.iv_ringtone_selected); view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); } RingtoneItem item = items.get(position); holder.tvName.setText(item.title); if (item.selected) { holder.tvName.setTextColor(getResources().getColor(R.color.white)); holder.ivSelected.setImageResource(R.drawable.ic_radio_button_checked); } else { holder.tvName.setTextColor(getResources().getColor(R.color.text_hui)); holder.ivSelected.setImageResource(R.drawable.ic_radio_button_unchecked); } return view; } } /** * 获取系统铃声 */ private void getSystemRingtones() { ringtoneItems.clear(); RingtoneManager manager = new RingtoneManager(this); manager.setType(RingtoneManager.TYPE_RINGTONE); cursor = manager.getCursor(); if (cursor != null && cursor.moveToFirst()) { do { String title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX); Uri uri = manager.getRingtoneUri(cursor.getPosition()); ringtoneItems.add(new RingtoneItem(title, uri)); } while (cursor.moveToNext()); cursor.close(); } } /** * 查找当前铃声在列表中的位置 */ private void setDefaultSelection() { for (int i = 0; i < ringtoneItems.size(); i++) { if (ringtoneItems.get(i).uri.equals(currentRingtoneUri)) { selectedPosition = i; ringtoneItems.get(i).selected = true; break; } } adapter.notifyDataSetChanged(); } /** * 设置选中的铃声 */ private void handleRingtoneSelection(int position) { RingtoneItem selectedItem = ringtoneItems.get(position); // 停止当前播放的铃声 if (currentRingtone != null && currentRingtone.isPlaying()) { currentRingtone.stop(); } // (重新)播放选中的铃声 currentRingtone = RingtoneManager.getRingtone(this, selectedItem.uri); currentRingtone.play(); // 更新选中状态 if (selectedPosition != -1) { ringtoneItems.get(selectedPosition).selected = false; } selectedItem.selected = true; selectedPosition = position; setAsDefaultRingtone(selectedItem.uri); adapter.notifyDataSetChanged(); } /** * 设置为系统默认铃声 * * @param uri 铃声Uri */ private void setAsDefaultRingtone(Uri uri) { try { RingtoneManager.setActualDefaultRingtoneUri( this, RingtoneManager.TYPE_RINGTONE, uri ); Log.d(TAG, "Ringtone set successfully: " + uri.toString()); } catch (SecurityException e) { Log.e(TAG, "Failed to set ringtone: " + e.getMessage()); // 处理权限问题 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { if (!Settings.System.canWrite(this)) { // 请求写入设置权限 Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } } } catch (Exception e) { Log.e(TAG, "Exception setting ringtone: " + e.getMessage()); } } /** * 铃声项数据类 * * @title 铃声名称 * @uri 铃声Uri * @selected 是否选中 */ private static class RingtoneItem { String title; Uri uri; boolean selected; public RingtoneItem(String title, Uri uri) { this.title = title; this.uri = uri; this.selected = false; } } @Override protected void onDestroy() { super.onDestroy(); if (currentRingtone != null && currentRingtone.isPlaying()) { currentRingtone.stop(); } if (cursor != null) { cursor.close(); } } } 上述代码出现了Android StaleDataException: Attempted to access a cursor after it has been closed报错,请帮忙优化修改
最新发布
07-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值