获取*气象台API 完整城市列表简单方式

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/get_data_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="@string/get_data" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/get_data_btn"
        android:layout_below="@+id/get_data_btn"/>

</RelativeLayout>

MainActivity.java

/**
 *    最近在看天气预报的相关知识,想寻找一个比较合适的API接口,终于找到了这篇文档
 * http://blog.csdn.net/lzqwebsoft/article/details/7054045
 * 里面详细说明的怎样从中国天气网获取天气信息,可是没用几天发现文中使用的获取城市
 * 列表的接口貌似被封了,导致原先的方法不使用,后悔但是没能及时将相关信息保存下来
 * ,以前是考虑每次实时的从网络上获取城市列表,以防信息有变,但是这种接口本身就是
 * 个不稳定的因素,所以还是得把相关信息下载下来。最后只得自己去分析网页,需找另外
 * 的接口,最后终于找到了,那就老老实实把这些数据保存到数据库里面吧。
 *    天气网把城市分为了3级
 *    1级列表获取地址:http://www.weather.com.cn/data/city3jdata/china.html。通过访问这个地址,天气
 *    网会返回一级省(自治区)的名称、ID信息;
 *    2级城市城市列表获取地址:http://www.weather.com.cn/data/city3jdata/provshi/10120.html。其中“10120”
 *    为一级城市的ID,返回结果是归属于该城市的2级省市的名称、ID;
 *    3级城市列表获取地址:http://www.weather.com.cn/data/city3jdata/station/1012002.html。其中“1012002”
 *    为2级省市ID,返回结果就是3级城市的名称和ID了。
 *    获取到3级城市的名称和ID之后,就可以根据上面那篇博客里的内容获取当地的天气信息了!
 *    */
package com.ns.getweathercity;

import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.content.ContentValues;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener{
    
    private Button mGetDataButton = null;
    private TextView mProgressTextView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        mGetDataButton = (Button)findViewById(R.id.get_data_btn);
        mGetDataButton.setOnClickListener(this);
        
        mProgressTextView = (TextView)findViewById(R.id.textView1);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.get_data_btn:
            new GetDataTask().execute();
            break;

        default:
            break;
        }        
    }

    private class GetDataTask extends AsyncTask<Void, Integer, Integer> {
        
        private HttpClient httpClient = null;
        
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        
        @Override
        protected Integer doInBackground(Void... params) {
            getHttpClient();
            
            CityDataHelper.getInstance(MainActivity.this).delete(null, null);
            
            //通过递归获取城市列表
            try {
                getCitys(1, "", "http://www.weather.com.cn/data/city3jdata/china.html");
            } catch (ClientProtocolException e) {
                Log.e("ns", "error", e);
                return -1;
            } catch (IOException e) {
                Log.e("ns", "error", e);
                return -1;
            }
            return 1;
        }
        
        /**这个函数的代码,参照http://blog.csdn.net/suiyuansanren/article/details/8663824这篇博文
         * 写的不错*/
        private synchronized HttpClient getHttpClient() {
            if(httpClient == null) {
                final HttpParams httpParams = new BasicHttpParams();  
                
                // timeout: get connections from connection pool
                ConnManagerParams.setTimeout(httpParams, 5000);  
                // timeout: connect to the server
                HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
                // timeout: transfer data from server
                HttpConnectionParams.setSoTimeout(httpParams, 5000); 
                
                // set max connections per host
                //ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(10));  
                // set max total connections
                ConnManagerParams.setMaxTotalConnections(httpParams, 20);
                
                // use expect-continue handshake
                HttpProtocolParams.setUseExpectContinue(httpParams, true);
                // disable stale check
                HttpConnectionParams.setStaleCheckingEnabled(httpParams, false);
                
                HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);  
                HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8); 
                  
                HttpClientParams.setRedirecting(httpParams, false);
                
                // set user agent
                String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";
                HttpProtocolParams.setUserAgent(httpParams, userAgent);     
                
                // disable Nagle algorithm
                HttpConnectionParams.setTcpNoDelay(httpParams, true); 
                
                HttpConnectionParams.setSocketBufferSize(httpParams, 8*1024);  
                
                // scheme: http and https
                SchemeRegistry schemeRegistry = new SchemeRegistry();  
                schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));  
                schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));

                ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);  
                httpClient = new DefaultHttpClient(manager, httpParams); 
            }        
            
            return httpClient;
        }
        
        private void getCitys(int level, String pid, String url) throws ClientProtocolException, IOException {
            Log.i("ns", "The url is " + url);
            HttpGet httpGet = null;

            HttpResponse httpResponse = null;
            String citys = null;
            String[] citys1Array = null;
            int index = 0;
            String cityName = null;
            String cityID = null;

            httpGet = new HttpGet(url);
            if (httpClient != null) {
                httpResponse = httpClient.execute(httpGet);
                if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    citys = EntityUtils.toString(httpResponse.getEntity(),
                            HTTP.UTF_8);
                    if (citys != null && citys.trim().length() > 0) {
                        citys1Array = citys.substring(1, citys.length() - 1)
                                .split(",");
                        for (int i = 0; i < citys1Array.length; i++) {
                            index = citys1Array[i].indexOf(":");
                            //当前城市的ID需要用上一级城市的ID拼接出来,但是有个别的三级城市直接是最终的ID了
                            //不知道天气网为什么要这么做
                            cityID = citys1Array[i].substring(1, index - 1);
                            if (level != 3 || cityID.length() < 9) {
                                cityID = pid + cityID;
                            }
                            
                            //这里把当前正在进行的操作提示处理,以确保正在工作
                            publishProgress(Integer.parseInt(cityID));
                            
                            cityName = citys1Array[i].substring(index + 2,
                                    citys1Array[i].length() - 1);

                            // 插入数据库
                            ContentValues values = new ContentValues();
                            values.put(CityContract.City.NAME, cityName);
                            values.put(CityContract.City.CITY_ID, cityID);
                            values.put(CityContract.City.LEVEL, level);
                            values.put(CityContract.City.PARENT_CITY_ID, pid);
                            CityDataHelper.getInstance(MainActivity.this)
                                    .insert(values);

                            // 递归下一级列表
                            if (level == 1) {
                                // 获取二级列表
                                getCitys(2, cityID,
                                        "http://www.weather.com.cn/data/city3jdata/provshi/"
                                                + cityID + ".html");
                            } else if (level == 2) {
                                // 获取三级列表
                                getCitys(3, cityID,
                                        "http://www.weather.com.cn/data/city3jdata/station/"
                                                + cityID + ".html");
                            } else if (level == 3) {
                                continue;
                            }

                        }
                    }
                }
            }

        }
        
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            mProgressTextView.setText(values[0].intValue() + "");
        }
        
        @Override
        protected void onPostExecute(Integer result) {
            super.onPostExecute(result);
            Toast.makeText(MainActivity.this, "数据拉取完毕", Toast.LENGTH_SHORT).show();
            //到这里,所有城市的名称、ID以及他们之间的关系就存放到数据库里面了,下次直接使用即可
        }
    }
}

CityContract.java

package com.ns.getweathercity;

import android.provider.BaseColumns;

public class CityContract {

    private CityContract() {}
    
    public abstract static class City implements BaseColumns {
        //数据库表名
        public static final String TABLE_NAME = "city";
        //城市名称
        public static final String NAME = "name";
        //城市级别
        public static final String LEVEL = "level";
        //城市ID
        public static final String CITY_ID = "city_id";
        //上一级城市ID
        public static final String PARENT_CITY_ID = "p_c_id";
    }

}

CityDataHelper.java

package com.ns.getweathercity;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class CityDataHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_NAME = "city.db";
    
    private static final String SQL_CREATE_STUDENT = "create table " + 
                                                    CityContract.City.TABLE_NAME + " (" + 
                                                    CityContract.City._ID + " INTEGER PRIMARY KEY, " + 
                                                    CityContract.City.NAME + " TEXT, " + 
                                                    CityContract.City.LEVEL + " INTEGER, " +
                                                    CityContract.City.CITY_ID + " TEXT, " +
                                                    CityContract.City.PARENT_CITY_ID + " TEXT)";
    
    private static CityDataHelper mDbHelper = null;
    
    public static CityDataHelper getInstance(Context context) {
        if (mDbHelper == null) {
            mDbHelper = new CityDataHelper(context);
        }
        return mDbHelper;
    }
    
    /**
     * constructor
     * 
     * @param context
     *            Context object used for create database
     */
    private CityDataHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建“city”表
        db.execSQL(SQL_CREATE_STUDENT);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
    
    public synchronized long insert(ContentValues values) {
        long id = getWritableDatabase().insert(CityContract.City.TABLE_NAME, null, values);
        return id;
    }
    
    public synchronized long update(ContentValues values, String whereClause, String[] whereArgs) {
        long id = getWritableDatabase().update(CityContract.City.TABLE_NAME, values, whereClause, whereArgs);
        return id;
    }
    
    public synchronized int delete(String whereClause, String[] whereArgs) {
        int count = getWritableDatabase().delete(CityContract.City.TABLE_NAME, whereClause, whereArgs);
        return count;
    }
    
    public synchronized Cursor query(String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) {
        return getReadableDatabase().query(CityContract.City.TABLE_NAME, columns, selection, selectionArgs, groupBy, having, orderBy);
    }
}