カスタム 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(){}
}
}