1

3つのクラスがあります。オートコンプリートテキストボックスを使用して、Webサービス(残りの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(これは、残りの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(My 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を配置する必要があるかどうか疑問に思います(試しましたが、機能しません)。私はちょっと混乱しています...何かポインタはありますか?

アプリケーションのデバッグ中に、関連付けられたArrayListに要素がある場合でも、ArrayAdapterのプロパティmObjectsがクリアされ、プロパティmOriginalValuesに最初にロードされた文字列が入力されていることに気付きました。

4

2 に答える 2

1

完全なコードベース(+データ)を見ずに、誰かがあなたのコードの失敗の理由を特定できるかどうかはわかりません。ただし、問題は、明らかな行エラーではなく、オートコンプリート関連のコード全体を設定する方法に起因すると思います。以下では、この問題のいくつかに対処しようとします(私の観点から):

まず、TextWatcherfromで、ユーザーがオートコンプリートテキストを変更するたびにaをに追加LiftSearchActivityするメソッドを呼び出します。私はあなたがこれを望んでいることを本当に疑っています、あなたはおそらくrefresh(またはupdate)メソッドを呼び出すための1つだけを持っていることを見て、それに新しいフィルターテキストを渡すことを検討する必要があります。ユーザーが電話を回転させると、構成が変更されたため、これらのフラグメントも再作成されます。getCities()FragmentActivityFragmentActivity

次に、CitiesResponderFragmentクラスでフラグメントのgetCities()メソッドを呼び出し(データがない場合)onActivityCreated、更新サービスを開始します(?!)。最初のポイントに関連して、多くの不要なクエリを実行する可能性があります。たとえば、ユーザーが4文字を入力した後、間違っていたために文字の1つを削除することにした場合、5つのフラグメントが追加されます。これは、サービスを開始/データのクエリにします。

そして最後に、内部でどのように機能するかを理解しているかどうかはわかりませんAutoCompleteTextView。ドロップダウンに提案を提供するために、AutoCompleteTextViewウィジェットはそのアダプター(adapter.getFilter())をフィルター処理し、フィルターに一致するアイテムを提案として表示します。しきい値を設定したかどうかはわかりませんが、AutoCompleteTextView最初に設定したときにアイテムの空のリストから開始すると、最初に入力された最初の3文字のオートコンプリートは空になりますActivity。空のリストから始めて新しいフラグメントを追加しないため、最初の2文字は何も表示されません(charSequence.length() < 2)。フラグメントの作成、サービスの開始、およびデータのフェッチのオーバーヘッドは、アダプターフィルタリングの作業を実行するよりもほぼ確実に大きくなるため、3番目の文字も何も表示されない可能性があります(最初は空のリストが表示されます) 。テストしたかどうかはわかりませんが、この4番目の文字から、アダプターにいくつかの要素が含まれているはずであり、フィルター処理で何かが表示されるはずです。アダプタをクリアして新しいデータを追加すると、そのデータは、に入力された次の文字でのみ使用できるようになりAutoCompleteTextViewます。

フィルタリングを行う適切な方法は、アダプターをさらに拡張し、データストアに新しいフィルター処理されたアイテムを照会するgetFilter()独自の実装を返すメソッドを実装することです。フィルタリングメソッドはバックグラウンドスレッドで実行されますが、少しの作業で、現在のロジックをとRESTコールバックFilterで実装できると思います。Service

于 2012-11-30T13:01:17.503 に答える
0

REST APIオートコンプリートの例を参照してください:https ://subversion.assembla.com/svn/rockitsearch-android/

これは私のサービスの一部ですが、独自のRESTAPIをAutoCompleteTextViewコントロールに統合する方法の例としても役立ちます。オートコンプリートのサードパーティサービスに興味がある場合は、www.rockitsearch.comにアクセスしてください。

于 2012-11-25T02:27:02.470 に答える