android.database.StaleDataException: Attempted to access a cursor after it has b

 

故障现象描述

1.新建图片便签

2.拍照生成图片,点击图片,便签应用挂掉,但是便签已经生成了。

分析log:android.database.StaleDataExceptionAttempted to access a cursor after it habeen

但是同样的代码在android2.2上边没有发生,在android4.0上边发生了,分析原因在于

android4.0的managedCursor /managedQuery会自动的close一个cursor,但是我们又手动的关闭了一次,所以导致了这个问题,解决方案是在4.0的代码去掉close这个操作。

 

解决这个问题的关键是对于log的分析和对于网络资料的查找,但是从代码中查找问题的发生点时,我的思路明显狭窄,没有找对地方,后来同事经验较丰富,找对了地方,解决起来就很快。

 

 

解决方法:

  1.  if(Integer.parseInt(Build.VERSION.SDK) < 14)  
  2.                 {  
  3.                     cursor.close();  
  4.                 }  

参考资料:

http://code.google.com/p/android/issues/detail?id=23746

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
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(); } } } java Android,上述代码出现了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、付费专栏及课程。

余额充值