在尝试找出如何在ExpandableListView
中突出显示所选群组的同时,我注意到一些奇怪的事情:getGroupView(...)
每隔几秒就会在我的BaseExpandableListAdapter
上被调用,此时似乎没有任何事情发生。我每次调用时都开始记录堆栈跟踪,看来我的整个布局都无效了。在日志中经常出现在它之前的东西,但并非总是如此,并且紧接在它之前的会有所不同。
01-07 13:49:58.423 22504-22504/com.mycompany.myapp D/JobListAdapter﹕ getGroupView 0, true, android.widget.LinearLayout@418166c8
01-07 13:49:58.426 22504-22504/com.mycompany.myapp D/JobListAdapter﹕ call stack
java.lang.RuntimeException
at com.mycompany.myapp.ui.map.JobListAdapter.getGroupView(JobListAdapter.java:93)
at android.widget.ExpandableListConnector.getView(ExpandableListConnector.java:445)
at android.widget.AbsListView.obtainView(AbsListView.java:2059)
at android.widget.ListView.measureHeightOfChildren(ListView.java:1249)
at android.widget.ListView.onMeasure(ListView.java:1160)
at android.view.View.measure(View.java:12773)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4788)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
at android.view.View.measure(View.java:12773)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:594)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:376)
at android.view.View.measure(View.java:12773)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4788)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
at android.view.View.measure(View.java:12773)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4788)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1374)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:663)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:553)
at android.view.View.measure(View.java:12773)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4788)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2103)
at android.view.View.measure(View.java:12773)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1149)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2583)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4508)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:809)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:576)
at dalvik.system.NativeStart.main(Native Method)
活动的布局在没有明显原因的情况下无效是否正常?我不认为布局中的任何内容都应该重新调整大小已经显示,除了可能每分钟只改变一次的时钟。
编辑:这是列表适配器。我已经添加了一些日志记录来验证事件总线上没有可能导致列表项刷新的活动。
public class JobListAdapter extends BaseExpandableListAdapter {
public static final String TAG = JobListAdapter.class.getSimpleName();
public static final int INVALID_ID = 0;
private final EventReceiver<JobStatusEvent> mJobStatusReceiver;
private final EventReceiver<JobUpdateEvent> mJobUpdateReceiver;
private final List<Job> mJobs = new ArrayList<Job>();
private final JobFormatter mJobFormatter;
private final JobListView mView;
private final Context mContext;
private final EventBus<JobStatusEvent> mJobStatusBus;
private final EventBus<JobUpdateEvent> mJobUpdateBus;
public JobListAdapter(final JobListView view, final Vehicle vehicle,
final EventBus<JobStatusEvent> jobStatusBus,
final EventBus<JobUpdateEvent> jobUpdateBus) {
mView = view;
mJobStatusBus = jobStatusBus;
mJobUpdateBus = jobUpdateBus;
mContext = view.getContext();
mJobFormatter = new JobFormatter(mContext);
vehicle.getAssignedAndLoadedJobs(mJobs);
notifyDataSetChanged();
mJobStatusReceiver = new EventReceiver<JobStatusEvent>() {
@Override
public void onEvent(final EventBus<JobStatusEvent> bus, final JobStatusEvent event) {
final Job job = event.getJob();
final JobStatus status = job.getStatus();
final int index = mJobs.indexOf(job);
if(status == JobStatus.ASSIGNED || status == JobStatus.LOADED) {
if(index == -1) {
mJobs.add(job);
notifyDataSetChanged();
}
}
else if(index != -1) {
mJobs.remove(index);
notifyDataSetChanged();
}
}
};
mJobStatusBus.register(mJobStatusReceiver);
mJobUpdateReceiver = new EventReceiver<JobUpdateEvent>() {
@Override
public void onEvent(final EventBus<JobUpdateEvent> bus, final JobUpdateEvent event) {
if(mJobs.contains(event.getJob())) {
notifyDataSetChanged();
}
}
};
mJobUpdateBus.register(mJobUpdateReceiver);
}
/**
* Causes this adapter to unregister its listeners.
*/
public void destroy() {
mJobStatusBus.unregister(mJobStatusReceiver);
mJobUpdateBus.unregister(mJobUpdateReceiver);
}
@Override
public View getGroupView(final int groupPosition, final boolean isExpanded, View view,
final ViewGroup parent) {
Log.debug(TAG, "call stack", new RuntimeException());
// Log.debug(TAG, "getGroupView: pos=" + groupPosition + ", exp=" + isExpanded);
// Log.debug(TAG, "getGroupId(groupPosition) = " + getGroupId(groupPosition));
// Log.debug(TAG, "mView.getSelectedGroupId() = " + mView.getSelectedGroupId());
final Job job = mJobs.get(groupPosition);
if(view == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
view = inflater.inflate(R.layout.job_list_header, parent, false);
}
// TODO more views in job_list_header
final TextView textView = (TextView) view.findViewById(R.id.job_number);
if(job.hasNumber()) {
String content = mContext.getString(R.string.job_number);
textView.setText(content.replace("{JOB}", job.getNumber()));
}
else if(job.isFlagTrip()) {
textView.setText(mContext.getString(R.string.flag_trip));
}
else {
textView.setText("???");
}
final boolean selected = getGroupId(groupPosition) == mView.getSelectedGroupId();
view.findViewById(R.id.selected_indicator).setVisibility(selected ? View.VISIBLE : View.GONE);
return view;
}
@Override
public View getChildView(final int groupPosition, final int childPosition,
final boolean isLastChild, View view, final ViewGroup parent) {
if(view == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
view = inflater.inflate(R.layout.job_list_details, parent, false);
}
final TextView textView = (TextView) view.findViewById(R.id.job_details);
// textView.setText(R.string.lorem_ipsum);
final Job job = mJobs.get(groupPosition);
textView.setText(mJobFormatter.format(job));
return view;
}
@Override
public int getGroupCount() {
return mJobs.size();
}
@Override
public boolean isEmpty() {
return mJobs.isEmpty();
}
@Override
public int getChildrenCount(int groupPosition) {
return 1; // always one child per group
}
@Override
public Object getGroup(int groupPosition) {
return mJobs.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
// the child is simply a different display of the group
return mJobs.get(groupPosition);
}
@Override
public long getGroupId(int groupPosition) {
return mJobs.get(groupPosition).getListViewId();
}
@Override
public long getChildId(int groupPosition, int childPosition) {
// note inversion
return -mJobs.get(groupPosition).getListViewId();
}
@Override
public long getCombinedGroupId(long groupId) {
return groupId;
}
@Override
public long getCombinedChildId(long groupId, long childId) {
return childId;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
public int findGroupPosition(final long groupId) {
// group IDs are always positive
if(groupId < 1) {
return -1;
}
for(int i = 0, limit = getGroupCount(); i < limit; ++i) {
if(getGroupId(i) == groupId) {
return i;
}
}
return -1;
}
}