0

カスタム BaseAdapter をまとめることができました。このアダプターは、リスト項目ごとに 3 つの TextView を表示するために使用されます。アクティビティ内に ListViewが1 つある場合、完全に機能します。

ただし、3 つのフラグメントを持つフラグメント化されたアクティビティを使用しています。そのうちの 2 つには、カスタム アダプターと XML を使用する必要がある ListView が含まれています。

これら 2 つの 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() をコンテキストとして受け取ります - これは両方で同じなので、これが問題の原因ですか? これを回避する方法はありますか、それともフラグメントのもう 1 つの欠点ですか?

カスタムアダプターはおおよそ次のとおりです。コードの任意のチャンクをいくつか取り出しました...

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(){}

}

}
4

1 に答える 1

0

アダプターのコードは問題ないようです。別のフラグメントで 2 つのリスト ビューを実行する場合と同様のことを行いました。(results は実際には offerResults と等しいと仮定しています)

リスト ビューへの接続方法に問題があるのではないでしょうか?

  • Adapter と listViews がすべて、アクティビティではなくフラグメントで参照されていることを確認してください。

  • アダプターを設定したかどうかを確認し、adapter.notifyDataSetChanged() を呼び出さずにそれを駆動するリストを変更します。

フラグメントとアダプターの宣言方法を参照すると、より便利になります:)

編集:

FragmentPagerAdapter の代わりに FragmentManager を使用して、2 つのフラグメントを FrameLayouts にインフレートするシステムを実行していました。

フラグメントが作成され、フラグメント ページャー アダプターで正しくアクセスされているかどうかを再確認します。これを行うには、getItem() から fragmentId をログに記録します。

また、 getItem(...) の記述方法にも注意してください。新しいフラグメントを生成し続けると、メモリ不足エラーがすぐに発生する可能性があるためです。代わりに、フラグメント マネージャーとタグを使用して新しいフラグメントの作成を管理することを検討します。

もう 1 つの考えは、必要に応じてリストを引き出せるように、スライド式の引き出しの中にリストをセットアップすることを検討することです。

編集 2: 次の変更を試してください。この方法では、リストはフラグメントのメモリ内に存在し、完了時に GC される可能性のある AsyncTask の一部ではありません。

 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(){}

}
于 2012-11-20T18:51:17.463 に答える