gpt4 book ai didi

android - 具有自动完成功能的不同步 ArrayAdapter

转载 作者:行者123 更新时间:2023-11-30 03:54:37 25 4
gpt4 key购买 nike

我有 3 个类(class),我希望使用自动完成文本框向用户显示来自 Web 服务(rest api)的某些数据(又名城市)。我已经在我自己的应用程序的各种功能上使用了这个实现,但是由于某种原因,textchangedlistener 中存在同步问题...

CitiesArrayAdapter.java(显示不同的 View ,在我的例子中是“城市,州”):

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(这是我从其余 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;
}

}

我得到了正确的结果。但是我的服务似乎没有在我的 Activity 中填充我的数组适配器,当我尝试显示我的第一个“城市”时,我的适配器什么都不包含。我想知道我是否必须更改 notifydatasetchanged(我试过了,但没有用)。我有点困惑...有任何指示吗?

在调试应用程序时,我注意到 mObjects 的属性即使关联的 ArrayList 已清除 ArrayAdapter元素,然后属性 mOriginalValues 被填充第一次加载字符串。

最佳答案

在没有看到完整的代码库(+ 数据)的情况下,我不知道是否有人可以指出您的代码失败的原因。但我认为问题更多来自于你设置整个自动完成相关代码的方式,而不是一些明显的行错误。下面我将尝试解决其中的一些问题(从我的角度来看):

首先,在TextWatcher来自 LiftSearchActivity你调用getCities()添加的方法,每次用户修改自动完成文本时,一个 FragmentActivity .我真的怀疑你想要这个,你应该看看只有一个 FragmentActivity在其上调用刷新(或更新)方法,将新的过滤器文本传递给它。如果用户旋转手机,这些 fragment 也会因为配置更改而重新创建。

其次,在CitiesResponderFragment你称之为 fragment 的类 getCities() onActivityCreated 中的方法(如果您没有任何数据)启动更新服务(?!)。现在与第一点相关,您最终可能会做很多不必要的查询,例如,如果用户输入 4 个字符,然后决定删除其中一个字符,因为它不正确,您最终会添加 5 个 fragment ,来自哪 3 个将使服务启动/查询数据。

最后,我不确定你是否理解 AutoCompleteTextView在引擎盖下工作。为了向下拉菜单提供建议 AutoCompleteTextView小部件将过滤其适配器(adapter.getFilter())并将与过滤器匹配的项目显示为建议。我不知道你是否在 AutoCompleteTextView 上设置了一些阈值但最初,当您第一次设置 Activity 时,输入的前 3 个字符的自动完成将是空的,因为您从一个空的项目列表开始。 .前两个字符不会显示任何内容,因为您从一个空列表开始并且没有添加任何新 fragment (charSequence.length() < 2)。第三个字符很可能也不会显示任何内容,因为创建 fragment 、启动服务和获取数据的开销几乎肯定会大于适配器过滤的工作(它仍然会看到最初的空列表) .我不知道你是否测试过,但是从第四个字符开始,适配器中应该有一些元素,并且过滤应该显示一些东西。清除适配器并在其中添加新数据只会使该数据可用于 AutoCompleteTextView 中输入的下一个字符。 .

进行过滤的正确方法是进一步扩展您的适配器并实现 getFilter()返回您自己的方法 Filter将在数据存储中查询新过滤项目的实现。过滤方法在后台线程上运行,只需做一些工作我认为您可以使用 Service 实现您当前的逻辑。和 REST 回调。

关于android - 具有自动完成功能的不同步 ArrayAdapter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13547475/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com