使用Yahoo Weather provider和AutoCompleteTextView的Android Weather应用(第1部分)

这篇文章是我们探索Yahoo Weather API的系列文章的第一篇。 我们的目标是构建一个应用程序,使用yahoo天气提供商为我们提供实际的天气状况。 在其他两个帖子中,我们已经讨论了其他天气提供商,例如openweathermap 。 如果您有兴趣,可以在这里这里看看。

在第一篇文章中,我们想分析如何使用yahoo api检索城市信息。 我们将假设您已经拥有yahoo开发者帐户,如果没有,您可以使用此链接创建它。 拥有免费的appid非常重要但这完全免费,但是必须使用yahoo api。 在探索yahoo api的同时,我们有机会描述一些有趣的Android UI组件,例如AutoCompleteTextView和Android中的XML解析。 我们的目标是拥有一个Android应用,该应用现在显示与用户输入的部分名称相匹配的城市列表,如下所示:

android_yahoo_weather_autocomplete [4]

雅虎·沃伊德

获取天气信息的第一步是检索woeid 。 yahoo用来标识城市/地区的空间ID。 然后,我们必须找到一种方法来从用户输入的城市名称中获取此错误信息。

从用户界面的角度来看,我们希望用户仅输入城市名称或部分名称,并且我们必须找到一种方法来获取与用户输入的数据和相应的woeid相匹配的城市列表:下面显示的api获取与我们输入的模式匹配的城市列表:

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

如果在浏览器中使用此api,您将获得一个XML文件,其中包含与city_name_pattern匹配的城市的信息列表。

Android Yahoo XML数据解析器

现在是时候创建一个XML解析器了,以便我们可以从使用上述api时获得的数据中提取信息。 第一步是创建一个保存城市信息的数据模型,在我们的例子中,这很简单:

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数据并进行解析。 它有一个简单的静态方法,可以接受我们用来获取城市列表的模式。 首先,我们打开一个HTTP连接,并将流传递给XML解析器:

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

然后,我们开始解析数据,寻找我们感兴趣的标签。 到目前为止,也考虑我们的数据模型,我们只对woeid城市名称国家/地区感兴趣。 XML中还有其他信息,但是我们现在不希望提取它们。

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();
}

下面的代码非常简单,在第1行,我们仅获得第一个XML事件,然后开始遍历XML文档,直到到达结尾为止。 在方法的最后,我们有一份清单,其中列出了我们一直在寻找的信息。

AutoCompleteTextView和带有过滤器的ArrayAdapter

一旦我们知道了如何从XML中获取数据,就必须向用户显示使用yahoo api获得的项目列表。 有几种方法可以实现此目标,我们将使用AutoCompleteTextView。 该组件在Android文档中定义为“ 一个可编辑的文本视图,该视图在用户键入时自动显示完成建议。 建议列表显示在一个下拉菜单中,用户可以从中选择一个项目以用。代替编辑框的内容 。” 满足我们的需求! 使用这个组件很简单,但是使用数组适配器以及我们如何过滤结果则稍微复杂一些。 通常,此组件与静态项目列表一起使用,在本例中,我们必须从远程服务器中检索它。 首先,我们实现一个扩展ArrayAdapter的自定义适配器,这非常简单:

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接口,则可以得到我们想要的结果。 因此,我们有:

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;
        }
..
}

在第4行,我们实现了Filter,它还有另外两种必须实现的方法。 在performFiltering方法中,我们进行HTTP调用并检索数据(第12行)。 显然我们可能遇到ANR问题,并且我们很清楚我们不应该在主线程中进行HTTP调用。 但是,如果您阅读有关performFiltering的文档,您会发现此方法在单独的线程中运行,因此我们不会有任何问题。

最后,我们可以在UI组件中设置适配器,即使用户单击某个项目也可以处理适配器:

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
   }
});

在下一篇文章中,我们将使用woied检索天气信息,敬请期待!

  • 源代码即将推出


翻译自: https://www.javacodegeeks.com/2014/02/android-weather-app-using-yahoo-weather-provider-and-autocompletetextview-part-1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值