NullPointerException when going back through activities
I'm debugging my application, and getting a 'strange' exception. It's not consistent and therefore really hard to solve. I'll post some code below.
The class that gives my exception:
private ArrayList<String> idList;
@Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
if ( idList == null )
{
idList = new ArrayList<String>();
}
}
@Override
public void finishFromChild( Activity child )
{
LocalActivityManager manager = getLocalActivityManager();
int index = idList.size()-1;
if ( index < 1 )
{
finish();
return;
}
manager.destroyActivity( idList.get( index ), true );
idList.remove( index ); index--;
String lastId = idList.get( index );
Activity lastActivity = manager.getActivity( lastId );
Intent lastIntent = lastActivity.getIntent();
Window newWindow = manager.startActivity( lastId, lastIntent );
setContentView( newWindow.getDecorView() );
}
public void startChildActivity( String id, Intent intent )
{
if ( "restart".equalsIgnoreCase( id ) )
{
idList.clear();
}
Window window = getLocalActivityManager().startActivity( id, intent.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP ) );
if ( window != null )
{
idList.add( id );
setContentView( window.getDecorView() );
}
}
public Activity getCurrentActivity()
{
int length = idList.size();
if ( idList.isEmpty() ) {
return null;
}
else
{
return getLocalActivityManager().getActivity( idList.get( length-1 ) );
}
}
@Override
public boolean onKeyDown( int keyCode, KeyEvent event )
{
if ( keyCode == KeyEvent.KEYCODE_BACK )
{
return true;
}
return super.onKeyDown( keyCode, event );
}
@Override
public boolean onKeyUp( int keyCode, KeyEvent event )
{
if ( keyCode == KeyEvent.KEYCODE_BACK )
{
onBackPressed();
return true;
}
return super.onKeyUp( keyCode, event );
}
@Override
public void onBackPressed()
{
int length = idList.size();
if ( length > 1 )
{
Activity current = getLocalActivityManager().getActivity( idList.get( length-1 ) );
current.finish();
}
}
The exception itself:
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): FATAL EXCEPTION: main
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): java.lang.NullPointerException
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.dezide.android.troubleshooter.view.TabGroupActivity.finishFromChild(TabGroupActivity.java:46)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.app.Activity.finish(Activity.java:3290)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.dezide.android.troubleshooter.view.TabGroupActivity.onBackPressed(TabGroupActivity.java:106)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.dezide.android.troubleshooter.view.TabGroupActivity.onKeyUp(TabGroupActivity.java:93)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.KeyEvent.dispatch(KeyEvent.java:1281)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.app.Activity.dispatchKeyEvent(Activity.java:2075)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1673)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:796)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:796)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:796)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.widget.TabHost.dispatchKeyEvent(TabHost.java:275)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:796)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:796)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1697)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1111)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.app.Activity.dispatchKeyEvent(Activity.java:2070)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1673)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.ViewRoot.deliverKeyEventToViewHierarchy(ViewRoot.java:2493)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2463)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.view.ViewRoot.handleMessage(ViewRoot.java:1752)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.os.Handler.dispatchMessage(Handler.java:99)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.os.Looper.loop(Looper.java:144)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at android.app.ActivityThread.main(ActivityThread.java:4937)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at java.lang.reflect.Method.invokeNative(Native Method)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at java.lang.reflect.Method.invoke(Method.java:521)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
09-30 08:44:12.571: ERROR/AndroidRuntime(10557): at dalvik.system.NativeStart.main(Native Method)
The problem is that it does not always fail at the same place. Sometimes I can press back 20 times before the exception occurs, sometimes only 5.
EDIT: Adding more code.
My GuideActivity, which is where you make the steps, and launches each of them as a new activity:
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
if ( "startguide".equalsIgnoreCase( getIntent().getStringExtra( "action" ) ) )
{
try
{
startGuide( getIntent().getStringExtra( "guide" ) );
}
catch( Exception e )
{
e.printStackTrace();
}
}
else if ( "nextstep".equalsIgnoreCase( getIntent().getStringExtra( "action" ) ) )
{
String session = getIntent().getStringExtra( "session" );
String step = getIntent().getStringExtra( "step" );
String response = getIntent().getStringExtra( "response" );
try
{
nextGuideStep( session, step, response );
}
catch( Exception e )
{
e.printStackTrace();
}
}
}
public GuideStep getCurrentStep()
{
return currentStep;
}
public void setCurrentStep( GuideStep currentStep )
{
this.currentStep = currentStep;
}
public void startGuide( String name ) throws Exception
{
GuideStep guideStep = model.startGuide( name );
currentStep = guideStep;
setContentView ( R.layout.main );
LinearLayout linearLayout = ( LinearLayout ) findViewById( R.id.linearLayout );
TextView stepTitle = ( TextView ) findViewById( R.id.stepTitle );
TextView explanation = ( TextView ) findViewById( R.id.explanation );
stepTitle.setText( guideStep.getStepTitle() );
if ( guideStep.getExplanation() != "" )
{
explanation.setText( Html.fromHtml( guideStep.getExplanation() ) );
}
responses = guideStep.getResponses();
ListView listView = new ListView( this );
linearLayout.addView( listView );
listView.setAdapter( new CustomAdapter( this, R.layout.list_item, responses ) );
listView.setTextFilterEnabled( true );
listView.setOnItemClickListener( new OnItemClickListener()
{
public void onItemClick( AdapterView<?> parent, View view,
int position, long id ) {
try
{
Intent i = new Intent().setClass( getParent(), GuideActivity.class );
i.putExtra( "action", "nextstep" );
i.putExtra( "session", currentStep.getSession() );
i.putExtra( "step", currentStep.getStep() );
i.putExtra( "response", currentStep.getResponse( position ).getId() );
TabGroupActivity parentActivity = ( TabGroupActivity )getParent();
parentActivity.startChildActivity( currentStep.getStepTitle(), i );
}
catch( Exception e )
{
e.printStackTrace();
}
}
});
}
public void nextGuideStep( String session, String step, String responseId ) throws Exception
{
GuideStep guideStep = model.nextGuideStep( session, step, responseId );
currentStep = guideStep;
setContentView ( R.layout.main );
LinearLayout linearLayout = ( LinearLayout ) findViewById( R.id.linearLayout );
TextView stepTitle = ( TextView ) findViewById( R.id.stepTitle );
TextView explanation = ( TextView ) findViewById( R.id.explanation );
TextView didThisAnswerYourQuestion = ( TextView ) findViewById( R.id.didThisAnswerYourQuestion );
ScrollView scrollView = ( ScrollView ) findViewById( R.id.scrollView );
stepTitle.setText( guideStep.getStepTitle() );
if ( guideStep.getExplanation() != "" )
{
explanation.setText( Html.fromHtml( guideStep.getExplanation() ) );
}
responses = guideStep.getResponses();
if ( guideStep.getStepTitle() != "" )
{
ListView listView = new ListView( this );
linearLayout.addView( listView );
listView.setAdapter( new CustomAdapter( this, R.layout.list_item, responses ) );
listView.setTextFilterEnabled( true );
listView.setOnItemClickListener( new OnItemClickListener() {
public void onItemClick( AdapterView<?> parent, View view,
int position, long id ) {
try
{
Intent i = new Intent().setClass( getParent(), GuideActivity.class );
i.putExtra( "action", "nextstep" );
i.putExtra( "session", currentStep.getSession() );
i.putExtra( "step", currentStep.getStep() );
i.putExtra( "response", currentStep.getResponse( position ).getId() );
TabGroupActivity parentActivity = ( TabGroupActivity )getParent();
parentActivity.startChildActivity( currentStep.getStepTitle(), i );
}
catch( Exception e )
{
e.printStackTrace();
}
}
});
}
else {
stepTitle.setVisibility( View.GONE );
didThisAnswerYourQuestion.setVisibility( View.GONE );
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT );
params.addRule( RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE );
params.height = 350;
scrollView.setLayoutParams( params );
}
}
public boolean availableForFeedback()
{
return currentStep != null;
}
}
My starting Activity:
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
try
{
populateSections();
}
catch( Exception e )
{
e.printStackTrace();
}
}
private void populateSections() throws Exception
{
setContentView( R.layout.sections );
ArrayList<XmlSection> sections = new ArrayList<XmlSection>();
Portal portal = model.getPortal();
sections = portal.getSections();
final ArrayList<XmlSection> tempSections = sections;
ListView listView = ( ListView ) findViewById( R.id.sectionList );
listView.setAdapter( new CustomAdapter( this, R.layout.list_item, sections ) );
listView.setTextFilterEnabled( true );
listView.setOnItemClickListener( new OnItemClickListener()
{
public void onItemClick( AdapterView<?> parent, View view,
int position, long id )
{
try
{
Intent i = new Intent().setClass( SectionActivity.this, JAndroidTroubleshooterActivity.class );
i.putExtra( "name", tempSections.get( position ).getName() );
startActivity( i );
}
catch( Exception e )
{
e.printStackTrace();
}
}
});
}
The activity that my main activity launches:
@Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
Resources res = getResources();
TabHost tabHost = getTabHost();
TabHost.TabSpec spec;
Intent intent;
intent = new Intent().setClass( this, TabGroupGuideActivity.class );
intent.putExtra( "name", getIntent().getStringExtra( "name" ) );
spec = tabHost.newTabSpec( "guides" ).setIndicator( "Guides",
res.getDrawable( R.drawable.guides ) )
.setContent( intent );
tabHost.addTab( spec );
intent = new Intent().setClass( this, TabGroupFaqActivity.class );
intent.putExtra( "name", getIntent().getStringExtra( "name" ) );
spec = tabHost.newTabSpec( "faqs" ).setIndicator( "FAQs",
res.getDrawable( R.drawable.faq ) )
.setContent( intent );
tabHost.addTab( spec );
}
private Activity getCurrentTab()
{
Activity activity = getLocalActivityManager().getActivity( getTabHost().getCurrentTabTag() );
return activity;
}
private void optionRestart()
{
if ( getCurrentTab() instanceof TabGroupFaqActivity )
{
Intent i = new Intent().setClass( this, FaqActivity.class );
TabGroupFaqActivity activity = ( TabGroupFaqActivity ) getCurrentActivity();
i.putExtra( "name", activity.getCurrentSection() );
activity.startChildActivity( "restart", i );
}
if ( getCurrentTab() instanceof TabGroupGuideActivity )
{
Intent i = new Intent().setClass( this, GuideListActivity.class );
TabGroupGuideActivity activity = ( TabGroupGuideActivity ) getCurrentActivity();
i.putExtra( "name", activity.getCurrentSection() );
activity.startChildActivity( "restart", i );
}
}
private void optionFeedback()
{
if ( getCurrentTab() instanceof TabGroupFaqActivity )
{
Activity currentTab = ( ( TabGroupFaqActivity ) getCurrentTab() ).getCurrentActivity();
Article currentArticle = ( ( FaqActivity ) currentTab ).getCurrentArticle();
if ( currentArticle != null )
{
Intent i = new Intent().setClass( this, FeedbackActivity.class );
i.putExtra( "perform", "feedbackfaq" );
i.putExtra( "title", currentArticle.getTitle() );
startActivity( i );
}
else
{
Toast toast = Toast.makeText( getApplicationContext(), "You have to select an article to submit feedback", 500 );
toast.show();
开发者_Python百科}
}
if ( getCurrentTab() instanceof TabGroupGuideActivity )
{
Activity currentTab = ( ( TabGroupGuideActivity ) getCurrentTab() ).getCurrentActivity();
GuideStep currentStep = ( ( GuideActivity ) currentTab ).getCurrentStep();
if ( currentStep != null && "false".equalsIgnoreCase( currentStep.getTerminalStep() ) )
{
Intent i = new Intent().setClass( this, FeedbackActivity.class );
i.putExtra( "perform", "feedbackguide" );
i.putExtra( "session", currentStep.getSession() );
i.putExtra( "action", currentStep.getStepTitle() );
i.putExtra( "title", currentStep.getGuideTitle() );
startActivity( i );
}
else
{
Toast toast = Toast.makeText( getApplicationContext(), "You cannot submit feedback for the last step of a guide", 500 );
toast.show();
}
}
}
private void optionHome()
{
Intent i = new Intent().setClass( this, SectionActivity.class );
i.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP );
startActivity( i );
}
@Override
public void onConfigurationChanged( Configuration newConfig )
{
super.onConfigurationChanged( newConfig );
}
@Override
public boolean onCreateOptionsMenu( Menu menu )
{
MenuInflater inflater = getMenuInflater();
inflater.inflate( R.menu.menu, menu );
return true;
}
@Override
public boolean onOptionsItemSelected( MenuItem item )
{
switch ( item.getItemId() )
{
case R.id.menuRestart:
optionRestart();
return true;
case R.id.menuHome:
optionHome();
return true;
case R.id.menuFeedback:
optionFeedback();
return true;
default:
return super.onOptionsItemSelected( item );
}
}
My tab group activity:
@Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
currentSection = getIntent().getStringExtra( "name" );
startChildActivity( "GuideListActivity",
new Intent( this, GuideListActivity.class ).putExtra( "name", getIntent().getStringExtra( "name" ) ) );
}
public String getCurrentSection()
{
return currentSection;
}
And last, my activity that list guides:
public void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState );
try
{
populateGuideList( getIntent().getStringExtra( "name" ) );
}
catch( Exception e )
{
e.printStackTrace();
}
}
public void populateGuideList( String name ) throws Exception
{
setContentView( R.layout.guides );
Section section = model.getSection( name );
guides = section.getGuides();
ListView listView = ( ListView ) findViewById( R.id.guideList );
listView.setAdapter( new CustomAdapter( this, R.layout.list_item, guides ) );
listView.setTextFilterEnabled( true );
listView.setOnItemClickListener( new OnItemClickListener()
{
public void onItemClick( AdapterView<?> parent, View view,
int position, long id )
{
try
{
XmlGuide guide = guides.get( position );
Intent i = new Intent().setClass( getParent(), GuideActivity.class );
i.putExtra( "guide", guide.getName() );
i.putExtra( "action", "startguide" );
TabGroupActivity parentActivity = ( TabGroupActivity )getParent();
parentActivity.startChildActivity( guide.getName(), i );
}
catch( Exception e )
{
e.printStackTrace();
}
}
});
}
I think it may help:
public void startChildActivity(String id, Intent intent) {
id+=System.currentTimeMillis();
//rest of your code.
}
Edit: it need a little elaboration.
There are Activity
A
, B
and C
- You start
A
with Id"A"
- then you start
B
with Id"B"
- then you start
C
with Id"C"
- and from C you again start another instance of
B
with id"B"
(it may happen, becauseB
may be a ResultListScreen which may called for several time with Load More type button)
The problem is that in ArrayList<String> idList
when you finish from last B
manager.destroyActivity( idList.get( index ), true );
line is called which destroys Activity
having id "B"
, which are 2 in stack.
both B
are deleted and C
is pushed. and when you finish C
and there is no B
in the stack but its Id is available is ArrayList<String> idList
and you get its Activity
which is null
if not found.
That's all.
id+=System.currentTimeMillis();
in this line of code you assign a unique id every time you start new Activity
by using System's current time.
NullPointerException mainly occurs when you are trying to direct to something that does not exist....For ex: You forget to add image in resource folder, and say setBackground(image) or maybe you forgot to mention an activity in the manifest file and are trying to access that activity using Intent.Make sure you have all the resources in your res folder and all activities mentioned in the manifest file
I found better solution here:
http://code.google.com/p/android/issues/detail?id=12359
If you are doing id+System.currentTimeMillis()
you could get in next problems:
- a+b = c+d sometimes, so there is small possibility that you still get NPE
- you need to store id somewhere to be able to close it for example
精彩评论