在 android 中恢复 activity 时出现 ClassCastException
ClassCastException when resuming activity in android
我正在尝试使用此代码
public class TabActivity extends SherlockFragmentActivity implements ActionBar.TabListener, OnItemSelectedListener
{
enum TabType
{
SEARCH, LIST, FAVORITES
}
// Tab back stacks
private HashMap<TabType, Stack<String>> backStacks;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Initialize ActionBar
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set back stacks
if (savedInstanceState != null)
{
// Read back stacks after orientation change
backStacks = (HashMap<TabType, Stack<String>>) savedInstanceState.getSerializable("stacks");
}
else
{
// Initialize back stacks on first run
backStacks = new HashMap<TabType, Stack<String>>();
backStacks.put(TabType.SEARCH, new Stack<String>());
backStacks.put(TabType.LIST, new Stack<String>());
backStacks.put(TabType.FAVORITES, new Stack<String>());
}
// Create tabs
bar.addTab(bar.newTab().setTag(TabType.SEARCH).setText("Search").setTabListener(this));
bar.addTab(bar.newTab().setTag(TabType.LIST).setText("List").setTabListener(this));
bar.addTab(bar.newTab().setTag(TabType.FAVORITES).setText("Favorites").setTabListener(this));
}
@Override
protected void onResume()
{
super.onResume();
// Select proper stack
Tab tab = getSupportActionBar().getSelectedTab();
Stack<String> backStack = backStacks.get(tab.getTag());
if (! backStack.isEmpty())
{
// Restore topmost fragment (e.g. after application switch)
String tag = backStack.peek();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
if (fragment.isDetached())
{
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.attach(fragment);
ft.commit();
}
}
}
@Override
protected void onPause()
{
super.onPause();
// Select proper stack
Tab tab = getSupportActionBar().getSelectedTab();
Stack<String> backStack = backStacks.get(tab.getTag());
if (! backStack.isEmpty())
{
// Detach topmost fragment otherwise it will not be correctly displayed
// after orientation change
String tag = backStack.peek();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
ft.detach(fragment);
ft.commit();
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
// Restore selected tab
int saved = savedInstanceState.getInt("tab", 0);
if (saved != getSupportActionBar().getSelectedNavigationIndex())
getSupportActionBar().setSelectedNavigationItem(saved);
}
@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
// Save selected tab and all back stacks
outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());
outState.putSerializable("stacks", backStacks);
}
@Override
public void onBackPressed()
{
// Select proper stack
Tab tab = getSupportActionBar().getSelectedTab();
Stack<String> backStack = backStacks.get(tab.getTag());
String tag = backStack.pop();
if (backStack.isEmpty())
{
// Let application finish
super.onBackPressed();
}
else
{
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
// Animate return to previous fragment
ft.setCustomAnimations(R.anim.slide_from_right, R.anim.slide_to_left);
// Remove topmost fragment from back stack and forget it
ft.remove(fragment);
showFragment(backStack, ft);
ft.commit();
}
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
// Select proper stack
Stack<String> backStack = backStacks.get(tab.getTag());
if (backStack.isEmpty())
{
// If it is empty instantiate and add initial tab fragment
Fragment fragment;
switch ((TabType) tab.getTag())
{
case SEARCH:
fragment = Fragment.instantiate(this, SearchFragment.class.getName());
break;
case LIST:
fragment = Fragment.instantiate(this, ListFragment.class.getName());
break;
case FAVORITES:
fragment = Fragment.instantiate(this, FavoritesFragment.class.getName());
break;
default:
throw new java.lang.IllegalArgumentException("Unknown tab");
}
addFragment(fragment, backStack, ft);
}
else
{
// Show topmost fragment
showFragment(backStack, ft);
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
// Select proper stack
Stack<String> backStack = backStacks.get(tab.getTag());
// Get topmost fragment
String tag = backStack.peek();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
// Detach it
ft.detach(fragment);
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft)
{
// Select proper stack
Stack<String> backStack = backStacks.get(tab.getTag());
if (backStack.size() > 1)
ft.setCustomAnimations(R.anim.slide_from_right, R.anim.slide_to_left);
// Clean the stack leaving only initial fragment
while (backStack.size() > 1)
{
// Pop topmost fragment
String tag = backStack.pop();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
// Remove it
ft.remove(fragment);
}
showFragment(backStack, ft);
}
private void addFragment(Fragment fragment)
{
// Select proper stack
Tab tab = getSupportActionBar().getSelectedTab();
Stack<String> backStack = backStacks.get(tab.getTag());
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Animate transfer to new fragment
ft.setCustomAnimations(R.anim.slide_from_left, R.anim.slide_to_right);
// Get topmost fragment
String tag = backStack.peek();
Fragment top = getSupportFragmentManager().findFragmentByTag(tag);
ft.detach(top);
// Add new fragment
addFragment(fragment, backStack, ft);
ft.commit();
}
private void addFragment(Fragment fragment, Stack<String> backStack, FragmentTransaction ft)
{
// Add fragment to back stack with unique tag
String tag = UUID.randomUUID().toString();
ft.add(android.R.id.content, fragment, tag);
backStack.push(tag);
}
private void showFragment(Stack<String> backStack, FragmentTransaction ft)
{
// Peek topmost fragment from the stack
String tag = backStack.peek();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
// and attach it
ft.attach(fragment);
}
// The following code shows how to properly open new fragment. It assumes
// that parent fragment calls its activity via interface. This approach
// is described in Android development guidelines.
@Override
public void onItemSelected(String item)
{
ItemFragment fragment = new ItemFragment();
Bundle args = new Bundle();
args.putString("item", item);
fragment.setArguments(args);
addFragment(fragment);
}
}
在我的应用程序中,使用选项卡进行导航。我知道,有很多不赞成使用的方法,但我想从这里开始。一切都很好,除非应用程序进入后台并需要恢复(经过更长的时间,我认为它已从 rams 中清除)。我得到
java.lang.ClassCastException: java.util.ArrayList cannot be cast to
java.util.Stack
调用时(代码中的 73 行)
Stack backStack = backStacks.get(tab.getTag());
怎么了?为什么它在 activity 第一次启动时有效,但 onResume 却给出 ANR?
我会说这是因为 backStacks.get(tab.getTag());
returns List
而不是 Stack
。试试这个:
List backStack = backStacks.get(tab.getTag());
您可能也不应该使用原始类型。
好的,我自己找到了解决方案。正如我发现的那样,JAVA 中的 HashMap 序列化存在问题,因此我将 HashMap 作为对象保存到缓存中,并在需要时从缓存中打开它。一切都按预期工作。
/**
* In case that there is kinda bug in JAVA serializing HASHMAP, backstacks hashmap is writing to cache as object.
*/
private void serializeBackStack() {
try {
FileOutputStream fos =
new FileOutputStream(getCacheDir() + "backstack.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(backStacks);
oos.close();
fos.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Hashmap with backstacks is getting from object saved in cahse.
*
* @return HashMap
*/
private HashMap<TabType, Stack<String>> deserializeBackStack() {
HashMap<TabType, Stack<String>> map = new HashMap<>();
try {
FileInputStream fis = new FileInputStream(getCacheDir() + "backstack.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
map = (HashMap<TabType, Stack<String>>) ois.readObject();
ois.close();
fis.close();
} catch (IOException ioe) {
ioe.printStackTrace();
return new HashMap<>();
} catch (ClassNotFoundException c) {
c.printStackTrace();
return new HashMap<>();
}
if (map != null)
return map;
else
return new HashMap<>();
}
我正在尝试使用此代码
public class TabActivity extends SherlockFragmentActivity implements ActionBar.TabListener, OnItemSelectedListener
{
enum TabType
{
SEARCH, LIST, FAVORITES
}
// Tab back stacks
private HashMap<TabType, Stack<String>> backStacks;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Initialize ActionBar
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set back stacks
if (savedInstanceState != null)
{
// Read back stacks after orientation change
backStacks = (HashMap<TabType, Stack<String>>) savedInstanceState.getSerializable("stacks");
}
else
{
// Initialize back stacks on first run
backStacks = new HashMap<TabType, Stack<String>>();
backStacks.put(TabType.SEARCH, new Stack<String>());
backStacks.put(TabType.LIST, new Stack<String>());
backStacks.put(TabType.FAVORITES, new Stack<String>());
}
// Create tabs
bar.addTab(bar.newTab().setTag(TabType.SEARCH).setText("Search").setTabListener(this));
bar.addTab(bar.newTab().setTag(TabType.LIST).setText("List").setTabListener(this));
bar.addTab(bar.newTab().setTag(TabType.FAVORITES).setText("Favorites").setTabListener(this));
}
@Override
protected void onResume()
{
super.onResume();
// Select proper stack
Tab tab = getSupportActionBar().getSelectedTab();
Stack<String> backStack = backStacks.get(tab.getTag());
if (! backStack.isEmpty())
{
// Restore topmost fragment (e.g. after application switch)
String tag = backStack.peek();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
if (fragment.isDetached())
{
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.attach(fragment);
ft.commit();
}
}
}
@Override
protected void onPause()
{
super.onPause();
// Select proper stack
Tab tab = getSupportActionBar().getSelectedTab();
Stack<String> backStack = backStacks.get(tab.getTag());
if (! backStack.isEmpty())
{
// Detach topmost fragment otherwise it will not be correctly displayed
// after orientation change
String tag = backStack.peek();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
ft.detach(fragment);
ft.commit();
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
// Restore selected tab
int saved = savedInstanceState.getInt("tab", 0);
if (saved != getSupportActionBar().getSelectedNavigationIndex())
getSupportActionBar().setSelectedNavigationItem(saved);
}
@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
// Save selected tab and all back stacks
outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());
outState.putSerializable("stacks", backStacks);
}
@Override
public void onBackPressed()
{
// Select proper stack
Tab tab = getSupportActionBar().getSelectedTab();
Stack<String> backStack = backStacks.get(tab.getTag());
String tag = backStack.pop();
if (backStack.isEmpty())
{
// Let application finish
super.onBackPressed();
}
else
{
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
// Animate return to previous fragment
ft.setCustomAnimations(R.anim.slide_from_right, R.anim.slide_to_left);
// Remove topmost fragment from back stack and forget it
ft.remove(fragment);
showFragment(backStack, ft);
ft.commit();
}
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
// Select proper stack
Stack<String> backStack = backStacks.get(tab.getTag());
if (backStack.isEmpty())
{
// If it is empty instantiate and add initial tab fragment
Fragment fragment;
switch ((TabType) tab.getTag())
{
case SEARCH:
fragment = Fragment.instantiate(this, SearchFragment.class.getName());
break;
case LIST:
fragment = Fragment.instantiate(this, ListFragment.class.getName());
break;
case FAVORITES:
fragment = Fragment.instantiate(this, FavoritesFragment.class.getName());
break;
default:
throw new java.lang.IllegalArgumentException("Unknown tab");
}
addFragment(fragment, backStack, ft);
}
else
{
// Show topmost fragment
showFragment(backStack, ft);
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
// Select proper stack
Stack<String> backStack = backStacks.get(tab.getTag());
// Get topmost fragment
String tag = backStack.peek();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
// Detach it
ft.detach(fragment);
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft)
{
// Select proper stack
Stack<String> backStack = backStacks.get(tab.getTag());
if (backStack.size() > 1)
ft.setCustomAnimations(R.anim.slide_from_right, R.anim.slide_to_left);
// Clean the stack leaving only initial fragment
while (backStack.size() > 1)
{
// Pop topmost fragment
String tag = backStack.pop();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
// Remove it
ft.remove(fragment);
}
showFragment(backStack, ft);
}
private void addFragment(Fragment fragment)
{
// Select proper stack
Tab tab = getSupportActionBar().getSelectedTab();
Stack<String> backStack = backStacks.get(tab.getTag());
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Animate transfer to new fragment
ft.setCustomAnimations(R.anim.slide_from_left, R.anim.slide_to_right);
// Get topmost fragment
String tag = backStack.peek();
Fragment top = getSupportFragmentManager().findFragmentByTag(tag);
ft.detach(top);
// Add new fragment
addFragment(fragment, backStack, ft);
ft.commit();
}
private void addFragment(Fragment fragment, Stack<String> backStack, FragmentTransaction ft)
{
// Add fragment to back stack with unique tag
String tag = UUID.randomUUID().toString();
ft.add(android.R.id.content, fragment, tag);
backStack.push(tag);
}
private void showFragment(Stack<String> backStack, FragmentTransaction ft)
{
// Peek topmost fragment from the stack
String tag = backStack.peek();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
// and attach it
ft.attach(fragment);
}
// The following code shows how to properly open new fragment. It assumes
// that parent fragment calls its activity via interface. This approach
// is described in Android development guidelines.
@Override
public void onItemSelected(String item)
{
ItemFragment fragment = new ItemFragment();
Bundle args = new Bundle();
args.putString("item", item);
fragment.setArguments(args);
addFragment(fragment);
}
}
在我的应用程序中,使用选项卡进行导航。我知道,有很多不赞成使用的方法,但我想从这里开始。一切都很好,除非应用程序进入后台并需要恢复(经过更长的时间,我认为它已从 rams 中清除)。我得到
java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Stack
调用时(代码中的 73 行)
Stack backStack = backStacks.get(tab.getTag());
怎么了?为什么它在 activity 第一次启动时有效,但 onResume 却给出 ANR?
我会说这是因为 backStacks.get(tab.getTag());
returns List
而不是 Stack
。试试这个:
List backStack = backStacks.get(tab.getTag());
您可能也不应该使用原始类型。
好的,我自己找到了解决方案。正如我发现的那样,JAVA 中的 HashMap 序列化存在问题,因此我将 HashMap 作为对象保存到缓存中,并在需要时从缓存中打开它。一切都按预期工作。
/**
* In case that there is kinda bug in JAVA serializing HASHMAP, backstacks hashmap is writing to cache as object.
*/
private void serializeBackStack() {
try {
FileOutputStream fos =
new FileOutputStream(getCacheDir() + "backstack.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(backStacks);
oos.close();
fos.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Hashmap with backstacks is getting from object saved in cahse.
*
* @return HashMap
*/
private HashMap<TabType, Stack<String>> deserializeBackStack() {
HashMap<TabType, Stack<String>> map = new HashMap<>();
try {
FileInputStream fis = new FileInputStream(getCacheDir() + "backstack.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
map = (HashMap<TabType, Stack<String>>) ois.readObject();
ois.close();
fis.close();
} catch (IOException ioe) {
ioe.printStackTrace();
return new HashMap<>();
} catch (ClassNotFoundException c) {
c.printStackTrace();
return new HashMap<>();
}
if (map != null)
return map;
else
return new HashMap<>();
}