이 예외가 나를 견디고 있습니다. 내 주요 활동 프로세스가 종료되고 내 확장 가능 목록 뷰의 널 포인터 예외로 인해 앱이 강제 종료 될 때까지. 이것은 내 첫 번째 안드로이드 애플 리케이션과 자바를 쓰는 처음이다 그래서 약간의 n00b입니다. 그것은 시간표 애플 리케이션이며 그것은 컨텐츠 제공자로부터 목록에 데이터를로드하기 위해 커서 로더를 사용하고 있습니다. 여기서 내가 뭘 잘못하고 있니? 미리 감사드립니다.ExpandableListAdapter getChildrenCount 활동이 복원되었을 때 null 포인터 예외가 발생했습니다.
로그 캣 :
12-03 00:21:42.235: E/AndroidRuntime(2341): FATAL EXCEPTION: main
12-03 00:21:42.235: E/AndroidRuntime(2341): Process: com.crevitus.timetable, PID: 2341
12-03 00:21:42.235: E/AndroidRuntime(2341): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.crevitus.timetable/com.crevitus.timetable.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.ActivityThread.access$800(ActivityThread.java:144)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.os.Handler.dispatchMessage(Handler.java:102)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.os.Looper.loop(Looper.java:135)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.ActivityThread.main(ActivityThread.java:5221)
12-03 00:21:42.235: E/AndroidRuntime(2341): at java.lang.reflect.Method.invoke(Native Method)
12-03 00:21:42.235: E/AndroidRuntime(2341): at java.lang.reflect.Method.invoke(Method.java:372)
12-03 00:21:42.235: E/AndroidRuntime(2341): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
12-03 00:21:42.235: E/AndroidRuntime(2341): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
12-03 00:21:42.235: E/AndroidRuntime(2341): Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
12-03 00:21:42.235: E/AndroidRuntime(2341): at com.crevitus.timetable.adapter.ExpandableListAdapter.getChildrenCount(ExpandableListAdapter.java:67)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.widget.ExpandableListConnector.refreshExpGroupMetadataList(ExpandableListConnector.java:563)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.widget.ExpandableListConnector.setExpandedGroupMetadataList(ExpandableListConnector.java:758)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.widget.ExpandableListView.onRestoreInstanceState(ExpandableListView.java:1340)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.view.View.dispatchRestoreInstanceState(View.java:13621)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.view.ViewGroup.dispatchThawSelfOnly(ViewGroup.java:2907)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.widget.AdapterView.dispatchRestoreInstanceState(AdapterView.java:795)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2893)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2893)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.view.View.restoreHierarchyState(View.java:13599)
12-03 00:21:42.235: E/AndroidRuntime(2341): at com.android.internal.policy.impl.PhoneWindow.restoreHierarchyState(PhoneWindow.java:1980)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.Activity.onRestoreInstanceState(Activity.java:1022)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.Activity.performRestoreInstanceState(Activity.java:977)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1161)
12-03 00:21:42.235: E/AndroidRuntime(2341): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2271)
12-03 00:21:42.235: E/AndroidRuntime(2341): ... 10 more
MainActivity 번호 :
package com.crevitus.timetable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import android.app.AlertDialog;
import android.app.LoaderManager;
import android.content.ContentResolver;
import android.content.CursorLoader;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ExpandableListView.OnGroupExpandListener;
import android.widget.Toast;
import com.crevitus.timetable.adapter.ExpandableListAdapter;
import com.crevitus.timetable.provider.TimetableContentProvider;
import com.crevitus.timetable.service.ReminderHandler;
public class MainActivity extends BaseActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
private ExpandableListAdapter listAdapter;
private ExpandableListView expListView;
private List<String> listDataHeader;
private HashMap<String, List<List<String>>> listDataChild;
private int lastExpandedPosition = -1;
private int gPosition, cPosition;
private static final int MONDAY = 0, TUESDAY = 1, WEDNESDAY = 2, THURSDAY = 3, FRIDAY = 4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
//get data from content provider
getLoaderManager().initLoader(MONDAY, null, this);
getLoaderManager().initLoader(TUESDAY, null, this);
getLoaderManager().initLoader(WEDNESDAY, null, this);
getLoaderManager().initLoader(THURSDAY, null, this);
getLoaderManager().initLoader(FRIDAY, null, this);
// get the listview
expListView = (ExpandableListView) findViewById(R.id.lvExp);
expListView.setLongClickable(true);
//initialise data collections
listDataHeader = new ArrayList<String>();
listDataChild = new HashMap<String, List<List<String>>>();
// Add header data
listDataHeader.add("Monday");
listDataHeader.add("Tuesday");
listDataHeader.add("Wednesday");
listDataHeader.add("Thursday");
listDataHeader.add("Friday");
//get adapter
listAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild);
// set list adapter
expListView.setAdapter(listAdapter);
// Listview on child click listener
expListView.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
//get data by position
String group = (String) listAdapter.getGroup(groupPosition);
List<String> childList = listDataChild.get(group).get(childPosition);
//launch view activity and pass data
Intent view = new Intent(getApplicationContext(), ViewActivity.class);
Bundle bundle = new Bundle();
bundle.putStringArray("Class", new String[] {childList.get(0), childList.get(1), childList.get(2), childList.get(3), childList.get(4), childList.get(5)});
view.putExtras(bundle);
startActivity(view);
return false;
}
});
expListView.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (ExpandableListView.getPackedPositionType(id) == ExpandableListView.PACKED_POSITION_TYPE_CHILD)
{
int groupPosition = ExpandableListView.getPackedPositionGroup(id);
int childPosition = ExpandableListView.getPackedPositionChild(id);
longClick(expListView, groupPosition, childPosition);
return true;
}
return false;
}
private void longClick(ExpandableListView expListView, int groupPosition, int childPosition) {
gPosition = groupPosition;
cPosition = childPosition;
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
// set title
alertDialogBuilder.setTitle("Delete Class?");
// set dialog message
alertDialogBuilder
.setMessage("Are you sure you want to delete the class?")
.setCancelable(false)
.setPositiveButton("Yes",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
String group = (String) listAdapter.getGroup(gPosition);
List<String> childList = listDataChild.get(group).get(cPosition);
ContentResolver cr = getContentResolver();
cr.delete(TimetableContentProvider.CONTENT_URI, TimetableContentProvider.KEY_ID + " = ?", new String[] {childList.get(0)});
listAdapter.deleteChild(gPosition, cPosition);
listAdapter.notifyDataSetChanged();
ReminderHandler.cancelAlarm(Integer.parseInt(childList.get(0)), getApplicationContext());
Toast.makeText(getApplicationContext(), "Class Deleted", Toast.LENGTH_SHORT).show();
}
})
.setNegativeButton("No",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
});//end longclick listener
expListView.setOnGroupExpandListener(new OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
if (lastExpandedPosition != -1 && groupPosition != lastExpandedPosition)
{
expListView.collapseGroup(lastExpandedPosition);
}
lastExpandedPosition = groupPosition;
}
});
}
@Override
public void onResume()
{
super.onResume();
getLoaderManager().restartLoader(MONDAY, null, this);
getLoaderManager().restartLoader(TUESDAY, null, this);
getLoaderManager().restartLoader(WEDNESDAY, null, this);
getLoaderManager().restartLoader(THURSDAY, null, this);
getLoaderManager().restartLoader(FRIDAY, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader loader = null;
switch(id)
{
case MONDAY:
loader = new CursorLoader(this,
TimetableContentProvider.CONTENT_URI,
null,
TimetableContentProvider.KEY_DAY_COLUMN + "=?", new String[] {"Monday"},
null);
break;
case TUESDAY:
loader = new CursorLoader(this,
TimetableContentProvider.CONTENT_URI,
null,
TimetableContentProvider.KEY_DAY_COLUMN + "=?", new String[] {"Tuesday"},
null);
break;
case WEDNESDAY:
loader = new CursorLoader(this,
TimetableContentProvider.CONTENT_URI,
null,
TimetableContentProvider.KEY_DAY_COLUMN + "=?", new String[] {"Wednesday"},
null);
break;
case THURSDAY:
loader = new CursorLoader(this,
TimetableContentProvider.CONTENT_URI,
null,
TimetableContentProvider.KEY_DAY_COLUMN + "=?", new String[] {"Thursday"},
null);
break;
case FRIDAY:
loader = new CursorLoader(this,
TimetableContentProvider.CONTENT_URI,
null,
TimetableContentProvider.KEY_DAY_COLUMN + "=?", new String[] {"Friday"},
null);
break;
}
return loader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
List<String> splitMon;
List<String> splitTues;
List<String> splitWed;
List<String> splitThurs;
List<String> splitFri;
List<List<String>> monday = new ArrayList<List<String>>();
List<List<String>> tuesday = new ArrayList<List<String>>();
List<List<String>> wednesday = new ArrayList<List<String>>();
List<List<String>> thursday = new ArrayList<List<String>>();
List<List<String>> friday = new ArrayList<List<String>>();
switch(loader.getId())
{
case MONDAY:
while(cursor.moveToNext())
{
splitMon = new ArrayList<String>();
splitMon.add(cursor.getString(0));
splitMon.add(cursor.getString(1));
splitMon.add(cursor.getString(2));
splitMon.add(cursor.getString(3));
splitMon.add(cursor.getString(4));
splitMon.add(cursor.getString(5));
monday.add(splitMon);
}
listDataChild.put(listDataHeader.get(0), monday);
break;
case TUESDAY:
while(cursor.moveToNext())
{
splitTues = new ArrayList<String>();
splitTues.add(cursor.getString(0));
splitTues.add(cursor.getString(1));
splitTues.add(cursor.getString(2));
splitTues.add(cursor.getString(3));
splitTues.add(cursor.getString(4));
splitTues.add(cursor.getString(5));
tuesday.add(splitTues);
}
listDataChild.put(listDataHeader.get(1), tuesday);
break;
case WEDNESDAY:
while(cursor.moveToNext())
{
splitWed = new ArrayList<String>();
splitWed.add(cursor.getString(0));
splitWed.add(cursor.getString(1));
splitWed.add(cursor.getString(2));
splitWed.add(cursor.getString(3));
splitWed.add(cursor.getString(4));
splitWed.add(cursor.getString(5));
wednesday.add(splitWed);
}
listDataChild.put(listDataHeader.get(2), wednesday);
break;
case THURSDAY:
while(cursor.moveToNext())
{
splitThurs = new ArrayList<String>();
splitThurs.add(cursor.getString(0));
splitThurs.add(cursor.getString(1));
splitThurs.add(cursor.getString(2));
splitThurs.add(cursor.getString(3));
splitThurs.add(cursor.getString(4));
splitThurs.add(cursor.getString(5));
thursday.add(splitThurs);
}
listDataChild.put(listDataHeader.get(3), thursday);
break;
case FRIDAY:
while(cursor.moveToNext())
{
splitFri = new ArrayList<String>();
splitFri.add(cursor.getString(0));
splitFri.add(cursor.getString(1));
splitFri.add(cursor.getString(2));
splitFri.add(cursor.getString(3));
splitFri.add(cursor.getString(4));
splitFri.add(cursor.getString(5));
friday.add(splitFri);
}
listDataChild.put(listDataHeader.get(4), friday);
break;
}
listAdapter.notifyDataSetChanged();
expListView.post(new Runnable() {
@Override
public void run() {
switch(Calendar.getInstance().get(Calendar.DAY_OF_WEEK)){
case Calendar.MONDAY:
expListView.expandGroup(0);
break;
case Calendar.TUESDAY:
expListView.expandGroup(1);
break;
case Calendar.WEDNESDAY:
expListView.expandGroup(2);
break;
case Calendar.THURSDAY:
expListView.expandGroup(3);
break;
case Calendar.FRIDAY:
expListView.expandGroup(4);
break;
case Calendar.SATURDAY:
expListView.expandGroup(0);
break;
case Calendar.SUNDAY:
expListView.expandGroup(0);
break;
}
}
});
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
// TODO Auto-generated method stub
}
}
ExpandableListAdapter : 그래서
package com.crevitus.timetable.adapter;
import java.util.HashMap;
import java.util.List;
import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import com.crevitus.timetable.R;
public class ExpandableListAdapter extends BaseExpandableListAdapter {
private Context _context;
private List<String> listGroupData;
private HashMap<String, List<List<String>>> listItemData;
public ExpandableListAdapter(Context context, List<String> listGroupData,
HashMap<String, List<List<String>>> listDataChild) {
this._context = context;
this.listGroupData = listGroupData;
this.listItemData = listDataChild;
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return listItemData
.get(listGroupData
.get(groupPosition))
.get(childPosition);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
List<String> childText = (List<String>) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.exp_list_item, null);
}
TextView sTime = (TextView) convertView.findViewById(R.id.sTime);
TextView modName = (TextView) convertView.findViewById(R.id.modName);
if(childText != null)
{
modName.setText(childText.get(1) + " - Room: " + childText.get(2));
sTime.setText(childText.get(4));
}
return convertView;
}
@Override
public int getChildrenCount(int groupPosition) {
return this.listItemData.get(this.listGroupData.get(groupPosition))
.size();
}
@Override
public Object getGroup(int groupPosition) {
return this.listGroupData.get(groupPosition);
}
@Override
public int getGroupCount() {
return this.listGroupData.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.list_group, null);
}
TextView lblListHeader = (TextView) convertView.findViewById(R.id.listGroup);
lblListHeader.setTypeface(null, Typeface.BOLD);
lblListHeader.setText(headerTitle);
return convertView;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public void deleteChild(int groupPosition, int childPosition)
{
listItemData.get(listGroupData.get(groupPosition)).remove(childPosition);
}
}
우수 답변 감사합니다. Java 지식이 없으므로 한 달 안에 다른 교과서와 함께이 앱으로 갔기 때문에 내 안드로이드 이론은 부족합니다./ 어쨌든, 몇 가지 추가해야합니다.어떤 이유로 인해 오리엔테이션 변경시 데이터를 다시로드하기 위해 onResume()에서 restartLoader를 호출해야합니다. 이 기사에 대한 나의 이해에도 불구하고. 마지막으로, listDataHeader는 해시 맵이 정렬되지 않기 때문에 여전히 하드 코딩 된 일 목록을 필요로합니다. –
Gotcha. 참고로 LinkedHashMap 대신 항상 LinkedHashMap을 사용할 수 있습니다. –