मैं AutoCompleteTextView का उपयोग कैसे करूं और इसे वेब API से डेटा के साथ पॉप्युलेट करूं?


82

मैं AutoCompleteTextViewअपनी गतिविधि में उपयोग करना चाहता हूं और वेब एपीआई को क्वेरी करके उपयोगकर्ता के प्रकार के रूप में डेटा को पॉप्युलेट करता हूं। मैं यह कार्य कैसे करूं?

क्या मैं एक नया वर्ग बनाता हूं और ओवरराइड AutoCompleteTextView.performFilteringकरता हूं, या क्या मैं एक कस्टम सूची एडेप्टर का उपयोग करता हूं और एक कस्टम प्रदान करता android.widget.Filterहूं जो प्रदर्शन को प्रभावित करता है?

या क्या मेरा अंतिम लक्ष्य प्राप्त करने का एक बेहतर तरीका है?

मैंने कुछ समान किया है, लेकिन यह त्वरित खोज बॉक्स के लिए था और इसमें एक सेवा को लागू करना शामिल था, लेकिन मेरा मानना ​​है कि मैं यहां क्या करना चाहता हूं।


10
भविष्य के दर्शकों के लिए एक बढ़िया लिंक :): makovkastar.github.io/blog/2014/04/12/…
Tina

जवाबों:


104

मैं एक समाधान के साथ आया था, मुझे नहीं पता कि यह सबसे अच्छा समाधान है, लेकिन यह बहुत अच्छी तरह से काम करता है। मैंने जो किया वह एक कस्टम एडेप्टर बनाया गया जो कि ArrayAdapter का विस्तार करता है। कस्टम एडेप्टर में मैं getFilter को ओवररोड करता हूं और अपने स्वयं के फ़िल्टर वर्ग का निर्माण करता हूं जो PerformFiltering से आगे निकल जाता है। यह एक नया थ्रेड शुरू करता है ताकि यह UI को बाधित न करे। नीचे एक नंगे पैर उदाहरण है।

MyActivity.java

public class MyActivity extends Activity {
    private AutoCompleteTextView style;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        style = (AutoCompleteTextView) findViewById(R.id.style);
        adapter = new AutoCompleteAdapter(this, android.R.layout.simple_dropdown_item_1line); 
        style.setAdapter(adapter);
    }
}

AutoCompleteAdapter.java

public class AutoCompleteAdapter extends ArrayAdapter<Style> implements Filterable {
    private ArrayList<Style> mData;

    public AutoCompleteAdapter(Context context, int textViewResourceId) {
        super(context, textViewResourceId);
        mData = new ArrayList<Style>();
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Style getItem(int index) {
        return mData.get(index);
    }

    @Override
    public Filter getFilter() {
        Filter myFilter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if(constraint != null) {
                    // A class that queries a web API, parses the data and returns an ArrayList<Style>
                    StyleFetcher fetcher = new StyleFetcher();
                    try {
                        mData = fetcher.retrieveResults(constraint.toString());
                    }
                    catch(Exception e) {
                        Log.e("myException", e.getMessage());
                    }
                    // Now assign the values and count to the FilterResults object
                    filterResults.values = mData;
                    filterResults.count = mData.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence contraint, FilterResults results) {
                if(results != null && results.count > 0) {
                notifyDataSetChanged();
                }
                else {
                    notifyDataSetInvalidated();
                }
            }
        };
        return myFilter;
    }
}

4
अच्छा समाधान - वास्तव में मुझे क्या चाहिए। अगर मैं पूछ सकता हूँ, हालांकि ... आप अपने simple_dropdown_item_1line लेआउट में एक शैली लौटाते हैं। आप अपनी शैली वर्ग से एक उचित मूल्य कैसे प्राप्त करते हैं? मेरे लिए, यह एक वर्ग है जिसे मैंने बनाया है और मैं चाहता हूं कि पाठ मूल्य getStyleName मेरी सूची आइटम में प्रदर्शित हो, लेकिन यह सरल वर्ग के नाम को प्रदर्शित करता है।
बगफिक्सर

7
@bugfixr अपनी कक्षा में एक सार्वजनिक विधि जोड़ें। मेरे उदाहरण में यह था: पब्लिक स्ट्रिंग स्ट्रिंग () {रिटर्न नाम; }
ए जे।

1
नोटिफाइडडैट इनवाइटिड () कॉल से सावधान रहें। इसका मतलब है कि बाद में एडॉप्टर कैंट का उपयोग किया जा सकता है।
विक्रम बोदीचेरला

1
लेकिन यह एक ही धागे में नेटवर्क अनुरोध कर रहा है, क्या performFilteringविधि गैर-यूआई थ्रेड में चल रही है?
भार्गव

2
@Tohid यह अभी भी सबसे अच्छा जवाब है, इसमें केवल एक चीज जोड़ी जा सकती है। यह एक विलंबित हैंडलर है जिसका उपयोग एपीआई कॉल को ट्रिगर करने के लिए किया जा सकता है। जैसा कि यहाँ दिखाया गया है: truiton.com/2018/06/…
KnowIT

7

ए जे पर विस्तार ऊपर दिए गए उत्तर, निम्नलिखित कस्टम एडेप्टर में सर्वर अनुरोधों और जोंस पार्सिंग की हैंडलिंग शामिल है:

class AutoCompleteAdapter extends ArrayAdapter<String> implements Filterable
{
    private ArrayList<String> data;
    private final String server = "http://myserver/script.php?query=";

    AutoCompleteAdapter (@NonNull Context context, @LayoutRes int resource)
    {
        super (context, resource);
        this.data = new ArrayList<>();
    }

    @Override
    public int getCount()
    {
        return data.size();
    }

    @Nullable
    @Override
    public String getItem (int position)
    {
        return data.get (position);
    }

    @NonNull
    @Override
    public Filter getFilter()
    {
        return new Filter()
        {
            @Override
            protected FilterResults performFiltering (CharSequence constraint)
            {
                FilterResults results = new FilterResults();
                if (constraint != null)
                {
                    HttpURLConnection conn = null;
                    InputStream input = null;
                    try
                    {
                        URL url = new URL (server + constraint.toString());
                        conn = (HttpURLConnection) url.openConnection();
                        input = conn.getInputStream();
                        InputStreamReader reader = new InputStreamReader (input, "UTF-8");
                        BufferedReader buffer = new BufferedReader (reader, 8192);
                        StringBuilder builder = new StringBuilder();
                        String line;
                        while ((line = buffer.readLine()) != null)
                        {
                            builder.append (line);
                        }
                        JSONArray terms = new JSONArray (builder.toString());
                        ArrayList<String> suggestions = new ArrayList<>();
                        for (int ind = 0; ind < terms.length(); ind++)
                        {
                            String term = terms.getString (ind);
                            suggestions.add (term);
                        }
                        results.values = suggestions;
                        results.count = suggestions.size();
                        data = suggestions;
                    }
                    catch (Exception ex)
                    {
                        ex.printStackTrace();
                    }
                    finally
                    {
                        if (input != null)
                        {
                            try
                            {
                                input.close();
                            }
                            catch (Exception ex)
                            {
                                ex.printStackTrace();
                            }
                        }
                        if (conn != null) conn.disconnect();
                    }
                }
                return results;
            }

            @Override
            protected void publishResults (CharSequence constraint, FilterResults results)
            {
                if (results != null && results.count > 0)
                {
                    notifyDataSetChanged();
                }
                else notifyDataSetInvalidated();
            }
        };
    }

और इसे उसी तरह उपयोग करें:

public class MyActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        AutoCompleteTextView textView = (AutoCompleteTextView) findViewById (R.id.style);
        int layout = android.R.layout.simple_list_item_1;
        AutoCompleteAdapter adapter = new AutoCompleteAdapter (this, layout); 
        textView.setAdapter (adapter);
    }
}

3

चु: यह देखने के लिए कि वस्तु कैसे दिखती है और वस्तु को अलिखित करने पर अधिक नियंत्रण प्राप्त करने के लिए, निम्नलिखित कार्य करें ...

    @Override
    public View getView (int position, View convertView, ViewGroup parent) {
        TextView originalView = (TextView) super.getView(position, convertView, parent); // Get the original view

        final LayoutInflater inflater = LayoutInflater.from(getContext());
        final TextView view = (TextView) inflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);

        // Start tweaking
        view.setText(originalView.getText());
        view.setTextColor(R.color.black);  // also useful if you have a color scheme that makes the text show up white
        view.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); // override the text size
        return view;
    }

2
private AutoCompleteUserAdapter userAdapter;
private AutoCompleteTextView actvName;
private ArrayList<SearchUserItem> arrayList;

actvName = findViewById(R.id.actvName);

actvName.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        actvName.setText(userAdapter.getItemNameAtPosition(position));
        actvName.setSelection(actvName.getText().toString().trim().length());
    }
});

actvName.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(final CharSequence s, int start, int before, int count) {
        if (actvName.isPerformingCompletion()) {
            // An item has been selected from the list. Ignore.
        } else {
            if (s.toString().toLowerCase().trim().length() >= 2) {
                getUserList(s.toString().toLowerCase().trim());
            }
        }
    }

    @Override
    public void afterTextChanged(Editable s) {

    }
});

private void getUserList(String searchText) {
    //Add data to your list after success of API call
    arrayList = new ArrayList<>();
    arrayList.addAll(YOUR_LIST);
    userAdapter = new AutoCompleteUserAdapter(context, R.layout.row_user, arrayList);
    getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            actvName.setAdapter(userAdapter);
            userAdapter.notifyDataSetChanged();
            actvName.showDropDown();
        }
    });        
}

AutoCompleteUserAdapter

/**
 * Created by Ketan Ramani on 11/07/2019.
 */
public class AutoCompleteUserAdapter extends ArrayAdapter<SearchUserItem> {

    private Context context;
    private int layoutResourceId;
    private ArrayList<SearchUserItem> arrayList;

    public AutoCompleteUserAdapter(Context context, int layoutResourceId, ArrayList<SearchUserItem> arrayList) {
        super(context, layoutResourceId, arrayList);
        this.context = context;
        this.layoutResourceId = layoutResourceId;
        this.arrayList = arrayList;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        try {
            if (convertView == null) {
                convertView = LayoutInflater.from(parent.getContext()).inflate(layoutResourceId, parent, false);
            }

            SearchUserItem model = arrayList.get(position);

            AppCompatTextView tvUserName = convertView.findViewById(R.id.tvUserName);
            tvUserName.setText(model.getFullname());
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return convertView;
    }

    public String getItemNameAtPosition(int position) {
        return arrayList.get(position).getName();
    }

    public String getItemIDAtPosition(int position) {
        return arrayList.get(position).getId();
    }
}

1
actvName.isPerformingCompletion () के लिए वोट करें जिससे मेरी हैंडलिंग बच गई।
रजत मेहरा

1

यहां एडॉप्टर क्लास का एक कोटलिन संस्करण है जो कमरे के माध्यम से स्थानीय डेटाबेस से डेटा लोड करता है:

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.Filter
import android.widget.Filterable
import android.widget.TextView
import ...MyFinderDatabase
import ...R
import ...model.SearchResult

class SearchCompleteAdapter(context: Context, val resourceId: Int): ArrayAdapter<SearchResult>(context, resourceId), Filterable {
    private val results = mutableListOf<SearchResult>()

    override fun getCount() = results.size

    override fun getItem(position: Int) = results[position]

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view = convertView ?: LayoutInflater.from(context).inflate(resourceId, parent, false)
        val textView = view.findViewById<TextView>(R.id.autocomplete_name)
        textView.text = getItem(position).fullName
        return view
    }

    override fun getFilter() = object : Filter(){
        override fun performFiltering(constraint: CharSequence?): FilterResults {
            val filterResults = FilterResults()
            val db = MyRoomDatabase.getDatabase(context.applicationContext)
            val dbResults = db.resultDao().findWithNameLike(String.format("%%%s%%", constraint.toString()))
            filterResults.values = dbResults
            filterResults.count = dbResults.size
            results.clear()
            results.addAll(dbResults)
            return filterResults
        }

        override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
            if((results != null) && (results.count > 0)){
                notifyDataSetChanged()
            }
            else{
                notifyDataSetInvalidated()
            }
        }

        override fun convertResultToString(resultValue: Any?): CharSequence {
            val searchResult = resultValue as SearchResult
            return searchResult.fullName
        }
    }
}

DAO विधि परिभाषा:

    @Query("select * from SearchResult where full_name like :name and type = 'USER_TYPE'")
fun findWithNameLike(name: String): List<SearchResult>

धन्यवाद! आपने अभी मुझे कुछ घंटे =) बचाया
बाराकुडा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.