我有 3 个课程,我希望使用自动完成文本框向用户显示来自 Web 服务(rest api)的某些数据(又名城市)。我已经在我自己的应用程序的各种功能上使用了这个实现,但由于某种原因,textchangedlistener 中存在同步问题......
CitiesArrayAdapter.java(显示不同的视图,在我的例子中是“城市,州”):
package com.android.lzgo.adapters;
import java.util.ArrayList;
import java.util.List;
import com.android.lzgo.activities.LiftSearchActivity;
import com.android.lzgo.activities.R;
import com.android.lzgo.models.City;
import com.android.lzgo.models.Lift;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class CitiesArrayAdapter extends ArrayAdapter<City> {
private static final String TAG = CitiesArrayAdapter.class.getName();
private final ArrayList<City> cities;
private int viewResourceId;
public CitiesArrayAdapter(Context context, int textViewResourceId, ArrayList<City> results) {
super(context, textViewResourceId, results);
this.cities = results;
this.viewResourceId = textViewResourceId;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// assign the view we are converting to a local variable
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(viewResourceId, null);
}
City i = cities.get(position);
Log.d(TAG, "Here is my value: " + i);
if (i != null) {
TextView tt = (TextView) v.findViewById(android.R.id.text1);
Log.d(TAG, "Name: " + i.getName() + ", " + i.getProvince_name());
if (tt != null){
tt.setText("Name: " + i.getName() + ", " + i.getProvince_name());
}
}
// the view must be returned to our activity
return v;
}
}
CitiesResponderFragment.java (这是我从我的 rest api 获取值的方式):
package com.android.lzgo.fragment;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import com.android.lzgo.activities.LiftSearchActivity;
import com.android.lzgo.definitions.Constants;
import com.android.lzgo.models.City;
import com.android.lzgo.service.LzgoService;
import com.google.gson.Gson;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.Toast;
public class CitiesResponderFragment extends LzgoResponderFragment {
private static String TAG = CitiesResponderFragment.class.getName();
private List<City> mCities;
ArrayAdapter<City> adapter;
private String enteredCharacters;
LiftSearchActivity activity;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activity = (LiftSearchActivity) getActivity();
// This gets called each time our Activity has finished creating itself.
getCities();
}
private void getCities() {
if (mCities == null && activity != null) {
Intent intent = new Intent(activity, LzgoService.class);
intent.setData(Uri.parse(Constants.REST_CITIES_AUTOCOMPLETE));
Bundle params = new Bundle();
params.putString("search", getenteredCharacters());
intent.putExtra(LzgoService.EXTRA_HTTP_VERB, LzgoService.GET);
intent.putExtra(LzgoService.EXTRA_PARAMS, params);
intent.putExtra(LzgoService.EXTRA_RESULT_RECEIVER, getResultReceiver());
// Here we send our Intent to our RESTService.
activity.startService(intent);
}
}
@Override
public void onRESTResult(int code, String result) {
Log.e(TAG, Integer.toString(code));
Log.e(TAG, result);
// Check to see if we got an HTTP 200 code and have some data.
if (code == 200 && result != null) {
mCities = getCitiessFromJson(result);
adapter = activity.getArrayAdapter();
adapter.clear();
for( City city : mCities){
//debugging
Log.d(TAG, "City : " + city.getName());
adapter.add(city);
adapter.notifyDataSetChanged();
}
getCities();
}
else {
Activity activity = getActivity();
if (activity != null && code == 400) {
Toast.makeText(activity, result, Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(activity, "Failed to load lzgo data. Check your internet settings.", Toast.LENGTH_SHORT).show();
}
}
private List<City> getCitiessFromJson(String json) {
ArrayList<City> cityList = new ArrayList<City>();
Gson gson = new Gson();
try {
JSONObject citiesWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray cities = citiesWrapper.getJSONArray("cities");
for (int i = 0; i < cities.length(); i++) {
//JSONObject city = cities.getJSONObject(i);
String jsonCity = cities.getString(i);
City city = gson.fromJson( jsonCity, City.class );
//Log.e(TAG, "Hurray! Parsed json:" + city.getString("name"));
//cityList.add(city.getString("name"));
cityList.add(city);
}
}
catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
return cityList;
}
public String getenteredCharacters() {
return enteredCharacters;
}
public void setenteredCharacters(String characters) {
this.enteredCharacters = characters;
}
}
LiftSearchActivity.java(我的 FragmentActivity):
package com.android.lzgo.activities;
import java.util.ArrayList;
import com.android.lzgo.adapters.CitiesArrayAdapter;
import com.android.lzgo.fragment.CitiesResponderFragment;
import com.android.lzgo.models.City;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.DatePicker;
public class LiftSearchActivity extends FragmentActivity{
private static final String TAG = LiftSearchActivity.class.getName();
// User lift input
private AutoCompleteTextView autoCityFrom;
private AutoCompleteTextView autoCityTo;
private DatePicker date;
private CitiesArrayAdapter adapter;
private ArrayList<City> mCities ;
int year , month , day;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lift_search);
mCities = new ArrayList<City>();
adapter = new CitiesArrayAdapter(this,
android.R.layout.simple_dropdown_item_1line, mCities);
autoCityFrom = (AutoCompleteTextView) findViewById(R.id.cityFrom);
autoCityTo = (AutoCompleteTextView) findViewById(R.id.cityTo);
adapter.setNotifyOnChange(true);
autoCityFrom.setAdapter(adapter);
autoCityTo.setAdapter(adapter);
autoCityFrom.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// no need to do anything
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (((AutoCompleteTextView) autoCityFrom).isPerformingCompletion()) {
return;
}
if (charSequence.length() < 2) {
return;
}
String query = charSequence.toString();
getCities(query);
}
public void afterTextChanged(Editable editable) {
}
});
autoCityTo.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// no need to do anything
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (((AutoCompleteTextView) autoCityTo).isPerformingCompletion()) {
return;
}
if (charSequence.length() < 2) {
return;
}
String query = charSequence.toString();
getCities(query);
}
public void afterTextChanged(Editable editable) {
}
});
date = (DatePicker) findViewById(R.id.dpResult);
}
public void searchLifts(View view) {
Intent intent = new Intent(this, LiftsResultActivity.class);
//While autocomplete doesn't work hardcore value...
intent.putExtra("from", Integer.toString(9357)); // Sherbrooke
intent.putExtra("to", Integer.toString(6193)); // Montreal
intent.putExtra("date", Integer.toString(date.getMonth()+1) + "-" + Integer.toString(date.getDayOfMonth()) + "-" + Integer.toString(date.getYear()));
startActivity(intent);
}
public void getCities(String query) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
CitiesResponderFragment responder = (CitiesResponderFragment) fm.findFragmentByTag("RESTResponder");
responder = new CitiesResponderFragment();
responder.setenteredCharacters(query);
ft.add(responder, "RESTResponder");
ft.commit();
}
public CitiesArrayAdapter getArrayAdapter() {
// TODO Auto-generated method stub
return adapter;
}
}
我得到了正确的结果。但是我的服务似乎没有在我的活动中填充我的数组适配器,当我尝试显示我的第一个“城市”时,我的适配器不包含任何内容。我想知道我是否必须放置一个 notifydatasetchanged (我试过了,但没有用)。我有点困惑......任何指针?
在调试应用程序时,我注意到 ArrayAdapter 的属性 mObjects 被清除,即使关联的 ArrayList 有元素,然后属性 mOriginalValues 被第一次加载的字符串填充。