zoukankan      html  css  js  c++  java
  • AutoCompleteTextView和自定义的CursorAdapter

    用雅虎天气接口和AutoCompleteTextView开发天气应用(1)

    这篇文章是Yahoo天气API系列文章的第一篇,我们的目标就是使用Yahoo提供的天气接口获取当前的气象情况。之前的两篇文章已经介绍过了其它的天气接口,比如openweathermap接口,如果你感兴趣的话,可以看看这两篇文章文章一文章二

    这篇文章中,我们主要介绍怎么用Yahoo的API检索出各个城市信息。假设你已经有了一个Yahoo开发者账户。如果还没有,那么可以通过这个链接注册一个(注册链接)。你必须拥有一个appid,虽然它是完全免费的,但是你在使用yahoo的API的时候必须用上它。在分析Yahoo的API的时候,我们顺便介绍一些有意思的Android上的控件比如AutoCompleteTextView和android上的XML解析器。我们最后要实现一个Android APP,当用户输入一部分城市的名字时,就可以显示出所有和用户输入所匹配的城市选项,如下图所示:

    android_yahoo_weather_autocomplete_thumb[2]

    Yahoo Woeid

    获得天气信息的第一步就是检索Woeid,这是Yahoo提供给开发者的一个特殊的ID,用来分辨城市/地区信息。我们需要根据用户输入的城市名称来获得这个woeid。

    从界面的角度上看,我们希望通过用户输入的城市名称或者城市名称的部分,加上对应的woeid来获取与之匹配的城市信息列表,我们可以使用下面的API来获取匹配某个公式的城市列表信息。

    http://where.yahooapis.com/v1/places.q(city_name_pattern);count=MAX_RESULT_SIZE?appid=your_app_id

    如果你用浏览器来执行这个API,那么你就可以得到一个xml文件,即匹配city_name_pattern这个式子的城市信息列表。

    在Android中解析Yahoo的xml数据

    现在我们要创建一个XML解析器来处理上一步中我们获取到的数据。首先我们要新建一个数据model(MVC中的模型,也就是javaBean),对于我们这个例子来说,很简单:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class CityResult {
     
        private String woeid;
        private String cityName;
        private String country;
     
        public CityResult() {}
        public CityResult(String woeid, String cityName, String country) {
            this.woeid = woeid;
            this.cityName = cityName;
            this.country = country;
        }
         // get and set methods
        @Override
        public String toString() {
            return cityName + "," + country;
        }
    }

    然后新建一个名为YahooClient的类进行解析。这个类主要负责遍历xml数据,然后进行转换。里面有一个静态方法可以接收一个模式(pattern),通过匹配这个模式可以获取城市信息列表。一开始,先要打开一个HTTP连接获取数据流信息,然后把这个数据流信息传给这个XML解析器,如下:

    1
    2
    3
    4
    5
    yahooHttpConn= (HttpURLConnection) (new URL(query)).openConnection();
    yahooHttpConn.connect();
     
    XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
    parser.setInput(new InputStreamReader(yahooHttpConn.getInputStream()));

    接下来可以开始转换数据了。根据我刚才新建的模型类,可以从xml中寻找我们需要的信息,我们需要Woeid、城市的名字和地区信息,xml文件中还有其它不需要关心的信息,我们可以不用理会。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    int event = parser.getEventType();
    CityResult cty = null;
    String tagName = null;
    String currentTag = null;
    // We start parsing the XML
    while (event != XmlPullParser.END_DOCUMENT) {
        tagName = parser.getName();
        if (event == XmlPullParser.START_TAG) {
           if (tagName.equals("place")) {
              // place Tag Found so we create a new CityResult
              cty = new CityResult();
              Log.d("Swa", "New City found");
          }
          currentTag = tagName;
          Log.d("Swa", "Tag ["+tagName+"]");
      }
      else if (event == XmlPullParser.TEXT) {
            // We found some text. let's see the tagName to know the tag related to the text
        if ("woeid".equals(currentTag))
            cty.setWoeid(parser.getText());
        else if ("name".equals(currentTag))
            cty.setCityName(parser.getText());
        else if ("country".equals(currentTag))
            cty.setCountry(parser.getText());
            // We don't want to analyze other tag at the moment
    }
    else if (event == XmlPullParser.END_TAG) {
        if ("place".equals(tagName))
            result.add(cty);
    }
    event = parser.next();
    }

    这段代码很简单。第一行获取第一个xml事件,然后开始遍历xml数据文件直到到达文档末尾。在这个方法结束的时候,就可以获取我们想要得到的城市列表数据了。

    AutoCompleteTextView和带过滤器的数组适配器

    在我们知道怎么利用Yahoo的API从xml文件中获取数据后,我们就要向用户展示这些数据。展示数据有很多中方式,我们使用AutoCompleteTextView。这个控件在Android文档中是这样定义的:“AutoCompleteTextView是一个可编辑文本视图(View)。当欧诺个户输入时会自动提示符合条件的备选项。提示信息在下拉菜单中显示。用户可以选中其中一项替换当前的编辑框内容。”,正好符合我们的需求。使用这个控件不难,但是使用数组适配器加上过滤操作就有点复杂了。通常来说,使用这个控件时都是使用静态的数据,而现在我们需要从远程服务器检索数据。首先要实现一个自定义的适配器,继承 ArrayAdapter十分简单,示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    private class CityAdapter extends ArrayAdapter<CityResult>  {
        private Context ctx;
        private List<CityResult> cityList = new ArrayList<CityResult>();
        public CityAdapter(Context ctx, List<CityResult> cityList) {
            super(ctx, R.layout.cityresult_layout, cityList);
            this.cityList = cityList;
            this.ctx = ctx;
        }
        @Override
        public CityResult getItem(int position) {
            if (cityList != null)
                return cityList.get(position);
            return null;
        }
        @Override
        public int getCount() {
            if (cityList != null)
                return cityList.size();
            return 0;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View result = convertView;
            if (result == null) {
                LayoutInflater inf = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                result = inf.inflate(R.layout.cityresult_layout, parent, false);
            }
            TextView tv = (TextView) result.findViewById(R.id.txtCityName);
            tv.setText(cityList.get(position).getCityName() + "," + cityList.get(position).getCountry());
            return result;
        }
        @Override
        public long getItemId(int position) {
            if (cityList != null)
                return cityList.get(position).hashCode();
            return 0;
        }  
    }

    注意:最重要的是我们要从远程服务器检索数据,然后可以通过实现Filterable接口来处理我们希望得到的数据,所以代码还需要:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    private class CityAdapter extends ArrayAdapter<CityResult> implements Filterable {
        ....
        @Override
        public Filter getFilter() {
            Filter cityFilter = new Filter() {
                @Override
                protected FilterResults performFiltering(CharSequence constraint) {
                    FilterResults results = new FilterResults();
                    if (constraint == null || constraint.length() < 2)
                        return results;
                    List<CityResult> cityResultList = YahooClient.getCityList(constraint.toString());
                    results.values = cityResultList;
                    results.count = cityResultList.size();
                    return results;
                }
                 
                @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    cityList = (List) results.values;
                    notifyDataSetChanged();
                }
            };
             
            return cityFilter;
        }
        ..
    }

    第四行我们实现了Filter接口,有两个方法需要实现,在performFiltering方法中我们执行HTTP调用然后检索数据。显然我们这样会导致ANR问题,因为我们知道不可以在主线程中发送HTTP请求。但是,如果你阅读performFiltering方法的文档的话,就会发现这个方法其实是在另外的线程中执行的。所以我们不用担心这个问题。

    最后,我们为AutoCompleteTextView设置适配器然后处理它的用户点击事件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
       AutoCompleteTextView edt = (AutoCompleteTextView) rootView.findViewById(R.id.edtCity);
       CityAdapter adpt = new CityAdapter(this.getActivity(), null);
       edt.setAdapter(adpt);
       edt.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          // We handle the onclick event and select the city chosen by the user
        }
    });

    在下一篇文章中我们再介绍怎么使用Woeid来获取天气数据,请继续期待吧。

    本文的源代码很快就会发布。

    ————————————————————————————————————————————————————————————

    Android 开发 AutoCompleteTextView结合自定义的适配器,查询数据库

    这里没有用CursorAdapter,而是自己继承BaseAdapter写了个适配器.
    与ListView不同,AutoCompleteTextView的适配器除了继承BaseAdapter外,还要实现Filterable接口。Filterable接口中有个getFilter方法,用于获取过滤器,我们需要自己写个继承Filter的过滤器,实现数据库查询。
    代码使用了androidannotations.

    1. import java.util.ArrayList;
    2. import java.util.List;
    3.  
    4. import android.content.Context;
    5. import android.view.LayoutInflater;
    6. import android.view.View;
    7. import android.view.ViewGroup;
    8. import android.widget.BaseAdapter;
    9. import android.widget.Filter;
    10. import android.widget.Filterable;
    11. import android.widget.ImageView;
    12. import android.widget.TextView;
    13. import cn.jtang.discussion.R;
    14. import cn.jtang.discussion.db.UserDB;
    15. import cn.jtang.discussion.mode.User;
    16.  
    17. import com.googlecode.androidannotations.annotations.Bean;
    18. import com.googlecode.androidannotations.annotations.EBean;
    19. import com.googlecode.androidannotations.annotations.RootContext;
    20.  
    21. @EBean
    22. public class LoginUsernameAdapter extends BaseAdapter implements Filterable {
    23. LayoutInflater mInflater;
    24. ArrayList<User> users;
    25. String key;
    26. @RootContext
    27. Context context;
    28. @Bean
    29. UserDB userDb;
    30. DBFilter filter;
    31. @Override
    32. public int getCount() {
    33. // TODO Auto-generated method stub
    34. if (users != null && users.size() > 0) {
    35. return users.size();
    36. }
    37. return 0;
    38. }
    39.  
    40. @Override
    41. public Object getItem(int position) {
    42. // TODO Auto-generated method stub
    43. return users.get(position);
    44. }
    45.  
    46. @Override
    47. public long getItemId(int position) {
    48. // TODO Auto-generated method stub
    49. return position;
    50. }
    51.  
    52. @Override
    53. public View getView(final int position, View convertView, ViewGroup parent) {
    54. // TODO Auto-generated method stub
    55. if (mInflater == null) {
    56. mInflater = LayoutInflater.from(context);
    57. }
    58. final User user = users.get(position);
    59.  
    60. View view = mInflater.inflate(R.layout.item_actv_username, null);
    61. TextView tv_username = (TextView) view.findViewById(R.id.tv_username);
    62. tv_username.setText(user.getUsername());
    63. ImageView iv_delete = (ImageView) view.findViewById(R.id.iv_delete);
    64. //添加点击事件
    65. iv_delete.setOnClickListener(new View.OnClickListener() {
    66. @Override
    67. public void onClick(View v) {
    68. // TODO Auto-generated method stub
    69. //点击后删除用户
    70. userDb.deleteUser(user);
    71. users.remove(position);
    72. notifyDataSetChanged();
    73. }
    74. });
    75. return view;
    76. }
    77. /**
    78. * 获取过滤器
    79. */
    80. @Override
    81. public Filter getFilter() {
    82. // TODO Auto-generated method stub
    83. if (filter == null) {
    84. filter = new DBFilter();
    85. }
    86. return filter;
    87. }
    88.  
    89. /**
    90. * 数据库查询过滤器
    91. *
    92. * @author Administrator
    93. *
    94. */
    95. private class DBFilter extends Filter {
    96. /**
    97. * 查询数据库
    98. */
    99. @Override
    100. protected FilterResults performFiltering(CharSequence prefix) {
    101. // TODO Auto-generated method stub
    102. //查询结果保存到FilterResults对象里
    103. FilterResults results = new FilterResults();
    104. List<User> queryUsers = userDb.query(prefix.toString());
    105. results.values = queryUsers;
    106. results.count = queryUsers.size();
    107. return results;
    108. }
    109.  
    110. /**
    111. * 更新UI
    112. */
    113. @Override
    114. protected void publishResults(CharSequence constraint, FilterResults results) {
    115. // TODO Auto-generated method stub
    116. List<User> queryUsers = (List<User>) results.values;
    117. //把结果读取出复制到users里
    118. if (users == null) {
    119. users = new ArrayList<User>();
    120. }
    121. if (users.size() > 0) {
    122. users.clear();
    123. }
    124.  
    125. if (queryUsers != null && queryUsers.size() > 0)
    126. for (User user : queryUsers) {
    127. users.add(user);
    128. notifyDataSetChanged();
    129. }
    130. }
    131.  
    132. }
    133. }
    134.  

    © 2013, 冰冻鱼. 请尊重作者劳动成果,复制转载保留本站链接! 应用开发笔记

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    http://zymic.iteye.com/blog/743538

          AutoCompleteTextView配合自定义的CursorAdapter(setAdapter()),可以帮助我们完成查找的功能.关键就在于类CursorAdapter.

          CursorAdapter是继承自BaseAdapter并且实现了接口Filterable 。所以在我们自己定义的CursorAdapter子类中就不需要在继承Filterable,但对于JRE是1.5以下的虚拟机来说。是要重写方法getFilter()的;

          要继承CursorAdapter类。必须实现的方法有:

           1)首先执行的是public Cursor runQueryOnBackgroundThread(CharSequence constraint),constraint就是我们输入的要查询的关键字;此方法产生查询到的所有数据的cursor.并将其返回给下一个函数;

           2)接下来执行方法public View newView(Context context, Cursor cursor, ViewGroup parent),cursor就是有第一种方法产生的.这个方法主要是产生一个个具体的承载cursor指向的数据的view类,最常见的是TextView;

           3)接下来执行方法public void bindView(View view, Context context, Cursor cursor) 。view就是第2步产生的。cursor是第一步产生的。显而易见,就是将两者进行绑定。

            但要注意的是,2和3是反复交替执行的。产生多少条数据(cursor.getcount())就执行多少轮。还有一点容易忽视的就是在xml文件中定义AutoCompleteTextView片段中一定要加入以下代码android:completionThreshold="1",他表示你最少要输入关键字的个数;

            下面的代码以查询联系人为例:

    Java代码  收藏代码
    1. package com.zymic.home;  
    2.   
    3. import android.app.Activity;  
    4. import android.content.ContentResolver;  
    5. import android.content.Context;  
    6. import android.database.Cursor;  
    7. import android.os.Bundle;  
    8. import android.provider.Contacts;  
    9. import android.provider.Contacts.People;  
    10. import android.view.LayoutInflater;  
    11. import android.view.View;  
    12. import android.view.ViewGroup;  
    13. import android.widget.AutoCompleteTextView;  
    14. import android.widget.CursorAdapter;  
    15. import android.widget.Filterable;  
    16. import android.widget.TextView;  
    17. import android.widget.Toast;  
    18.   
    19. public class AutoTextViewEx extends Activity {  
    20.     private AutoCompleteTextView autoTextView;  
    21.     private Cursor cursor;  
    22.     //  
    23.     private static final String[] PEOPLE_PROJECTION = new String[] {  
    24.         Contacts.People._ID,  
    25.         Contacts.People.PRIMARY_PHONE_ID,  
    26.         Contacts.People.TYPE,  
    27.         Contacts.People.NUMBER,  
    28.         Contacts.People.LABEL,  
    29.         Contacts.People.NAME,  
    30.     };  
    31.     //  
    32.     @Override  
    33.     public void onCreate(Bundle savedInstanceState) {  
    34.         super.onCreate(savedInstanceState);  
    35.         setContentView(R.layout.main);  
    36.         //  
    37.         autoTextView=(AutoCompleteTextView)findViewById(R.id.autotextview);  
    38.         cursor=getApplicationContext().getContentResolver().query(People.CONTENT_URI, PEOPLE_PROJECTION, null, null, null);  
    39.         MyAdapter adapter=new MyAdapter(this,cursor);  
    40.         autoTextView.setAdapter(adapter);  
    41.     }  
    42.     //  
    43.     public class MyAdapter extends CursorAdapter implements Filterable{  
    44.         Cursor cursor;  
    45.         public MyAdapter(Context context, Cursor c) {  
    46.             super(context, c);  
    47.             // TODO Auto-generated constructor stub  
    48.         }  
    49.   
    50.         @Override  
    51.         public void bindView(View view, Context context, Cursor cursor) {  
    52.             ((TextView)view).setText(cursor.getString(5));  
    53.             Toast.makeText(getApplicationContext(), "bindView", Toast.LENGTH_SHORT).show();  
    54.         }  
    55.   
    56.         @Override  
    57.         public View newView(Context context, Cursor cursor, ViewGroup parent) {  
    58.             LayoutInflater inflater = (LayoutInflater)context.getSystemService (  
    59.               Context.LAYOUT_INFLATER_SERVICE);  
    60.             TextView view=(TextView) inflater.inflate(android.R.layout.simple_dropdown_item_1line, null);  
    61.             //view.setText(cursor.getString(5));  
    62.             Toast.makeText(getApplicationContext(), "newView", Toast.LENGTH_SHORT).show();  
    63.             return view;  
    64.         }  
    65.   
    66.         @Override  
    67.         public Cursor runQueryOnBackgroundThread(CharSequence constraint) {  
    68.             //UPPER(Contacts.People.NAME)  
    69.             String where="UPPER("+Contacts.People.NAME+") GLOB ?";  
    70.             String[]to=new String[]{"*"+constraint.toString().toUpperCase()+"*"};  
    71.             cursor=getApplicationContext().getContentResolver().query(People.CONTENT_URI, PEOPLE_PROJECTION,  
    72.                     where, to, null);  
    73.             //System.out.println(cursor);  
    74.             Toast.makeText(getApplicationContext(), "runQuery", Toast.LENGTH_SHORT).show();  
    75.             return cursor;  
    76.         }  
    77.           
    78.           
    79.     }  
    80. }  
  • 相关阅读:
    dede织梦调取一二三级栏目名及栏目下的内容列表的方法
    Maven 加载ojdbc14.jar报错,解决方法
    vue.set动态新增对象属性,触发dom渲染
    object_funs.py
    module+standard library.py
    function.py
    exception.py
    assign.py
    if_test.py
    hello.py
  • 原文地址:https://www.cnblogs.com/bigben0123/p/4284143.html
Copyright © 2011-2022 走看看