我设法组建了一个自定义BaseAdapter。此适配器用于为每个列表项显示三个TextView。当活动中有一个 ListView时,它非常完美。
但是,我正在使用带有3个片段的碎片活动 - 其中2个片段包含需要使用我的自定义适配器和XML的ListView。
在加载这两个ListView时,在第一个 ListView加载时触发onItemClickListener会导致以下错误:
11-20 18:02:15.295: E/AndroidRuntime(18563): java.lang.IllegalStateException:
The content of the adapter has changed but ListView did not receive a
notification. Make sure the content of your adapter is not modified from
a background thread, but only from the UI thread. [in ListView(2131165192,
class android.widget.ListView) with
Adapter(class com.my.project.Adapter_CustomList)]
我不希望适配器发生变化 - 每个ListView适配器都使用新的Adapter_CustomList()所以我不确定为什么它们被引用为同一个适配器?
适配器将getActivity()作为上下文 - 因为这两者都是相同的,这会导致问题吗?有什么方法围绕这个,或者这是片段的另一个缺点吗?
自定义适配器大致如下,我已经采取了一些任意的代码块...
public class Adapter_CustomList extends BaseAdapter {
private static ArrayList<Custom> results;
private LayoutInflater mInflater;
public Adapter_CustomList(Context context, ArrayList<Custom> res) {
results = res;
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return results.size();
}
public Object getItem(int position) {
return results.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.custom_row_view, null);
holder = new ViewHolder();
//Set ViewHolder vars from inflated view
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
//Sets the TextViews
return convertView;
}
static class ViewHolder {
//Contains the TextView text vars
}
}
活动正在使用FragmentPagerAdapter(由Eclipse生成):
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
Fragment fragment;
switch (i){
case 1:
fragment = new Frag_ListOne();
break;
case 2:
fragment = new Frag_ListTwo();
break;
default:
fragment = new Frag_Temporary();
break;
}
return fragment;
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0: return getString(R.string.main_fragment1).toUpperCase();
case 1: return getString(R.string.main_fragment2).toUpperCase();
case 2: return getString(R.string.main_fragment3).toUpperCase();
}
return null;
}
}
片段示例,两者几乎相同但具有唯一的布局文件。
public class Frag_ListOne extends Fragment {
private ListView ListView;
private Adapter_CustomList listAdapter;
private Fetcher fetcher;
public Frag_ListOne(){}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
return inflater.inflate(R.layout.frag_list_one, container, false);
}
@Override
public void onStart(){
super.onStart();
ListView = (ListView) getActivity().findViewById(R.id.frag_one_list);
ListView.setEmptyView(getActivity().findViewById(R.id.frag_one_list_spinner));
if (listAdapter != null){
setListAdapter();
} else {
//This will always be called for now....
sendRequest();
}
}
private void sendRequest(){
fetcher = new Fetcher();
fetcher.execute("http://myapiurl.com");
}
private void cancelFetch(){
if (fetcher != null &&
(fetcher.getStatus() == AsyncTask.Status.PENDING || fetcher.getStatus() == AsyncTask.Status.RUNNING)){
fetcher.cancel(true);
}
}
private void displayError(String errMsg){
//Log errMsg
}
private void createListAdapter(ArrayList<Result> res){
listAdapter = new Adapter_CustomList(getActivity(), res);
setListAdapter();
}
private void setListAdapter(){
ListView.setAdapter(listAdapter);
ListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
Result r = (Result) ListView.getItemAtPosition(position);
Intent intent = new Intent(getActivity(), ViewResultActivity.class);
intent.putExtra(F_List.INTENT_VIEW_RESULT_OBJ, r);
startActivity(intent);
}
});
}
//Extended AsyncTask, essentially
public class Fetcher extends JSONRequest{
@Override
protected void onSuccess(JSONObject req, JSONObject res){
if (req != null && res != null){
try{
JSONArray jsons = res.getJSONArray("results");
ArrayList<Result> res = new ArrayList<Result>();
if (jsons.length() > 0){
for (int i=0;i<jsons.length();i++){
JSONObject jo = jsons.getJSONObject(i);
r = new Result();
r.setLineOne(jo.getInt("line1"));
r.setLineTwo(jo.getString("line2"));
r.setLineThree(jo.getString("line3"));
res.add(r);
}
createListAdapter(res);
} else {
//Nothing found
}
} catch (JSONException e){}
} else {
//Null received
}
}
@Override
protected void onError(String errMsg){}
@Override
protected void onCancel(){}
}
}
答案 0 :(得分:0)
适配器代码看起来没问题 - 我做了类似的事情,我在不同的片段中运行两个列表视图。 (我假设结果实际上等于offerResults)
也许您附加到列表视图的方式存在问题?
确保在片段中引用了Adapter和listViews,而不是活动。
检查您是否设置了适配器,然后更改驱动它的列表而不调用adapter.notifyDataSetChanged()
参考Fragments和声明适配器的方式可以更多地使用:)
修改强>
我正在运行一个系统,我会使用FragmentManager而不是FragmentPagerAdapter将2个片段扩展到FrameLayouts。
我会仔细检查片段寻呼机适配器中是否正在创建和正确访问片段。您可以通过从getItem()
记录fragmentId来完成此操作还要小心编写getItem(...)的方式,因为如果你不断产生新的碎片,这会很快导致内存不足错误。相反,我会考虑使用片段管理器和标签来管理新片段的创建。
另一个想法是考虑在滑动抽屉内设置列表,以便他们可以根据需要将它们拉出来。
编辑2: 尝试以下更改 - 这样列表就存在于片段的内存中,而不是AsyncTask的一部分,它可能在完成后进行GC。
private ArrayList<Result> resultList = new ArrayList<Result>();
private Adapter_CustomList adapter = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.frag_list_one, container, false);
listView = (ListView) v.findViewById(R.id.frag_one_list);
listView.setEmptyView(v.findViewById(R.id.frag_one_list_spinner));
adapter = new Adapter_CustomList(getActivity(), resultList);
listView.setAdapter(adapter);
}
@Override
public void onStart(){
super.onStart();
}
//Extended AsyncTask, essentially
public class Fetcher extends JSONRequest{
@Override
protected void onSuccess(JSONObject req, JSONObject res){
if (req != null && res != null){
try{
JSONArray jsons = res.getJSONArray("results");
if (jsons.length() > 0){
for (int i=0;i<jsons.length();i++){
JSONObject jo = jsons.getJSONObject(i);
r = new Result();
r.setLineOne(jo.getInt("line1"));
r.setLineTwo(jo.getString("line2"));
r.setLineThree(jo.getString("line3"));
resultList.add(r);
}
adapter.notifyDataSetChanged();
} else {
//Nothing found
}
} catch (JSONException e){}
} else {
//Null received
}
}
@Override
protected void onError(String errMsg){}
@Override
protected void onCancel(){}
}