zoukankan      html  css  js  c++  java
  • 10天学安卓-第六天

    经过前几天的学习,我们的天气预报程序已经可以把天气正常的呈现出来了,正如之前说的,现在的APP只能显示固定地区的天气,那么我们要怎样才能显示我们本身所在地的天气呢?

    Android定位

    Android系统本身提供了三种定位方式,分别是网络、基站和GPS,主要利用的是LocationManager、TelephonyManager相关的类库,但是因为一些原因,Google的API在国内访问经常出现问题,所以在这里我就不对这些API做介绍了,有想了解的可以自行查询相关资料。

    百度地图定位

    除了Android本身提供的定位功能外,在国内也有很多供我们使用的定位系统,比如百度地图、高德地图都提供了相应的功能,我这里主要介绍一下百度地图的使用方式。

    需要到 http://lbsyun.baidu.com/sdk/download?selected=location 下载定位功能的开发包,然后把开发包的内容放到libs文件夹,这样我们就引入了百度地图定位功能的API。

    然后,开工吧。

    配置Manifest

    首先添加定位功能所需要的权限,还记得添加到哪吧。

        <!-- 这个权限用于进行网络定位 -->
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <!-- 这个权限用于访问GPS定位 -->
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <!-- 获取运营商信息,用于支持提供运营商信息相关的接口 -->
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位 -->
        <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
        <!-- 用于读取手机当前的状态 -->
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据 -->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <!-- SD卡读取权限,用户写入离线定位数据 -->
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
        <!-- 允许应用读取低级别的系统日志文件 -->
        <uses-permission android:name="android.permission.READ_LOGS" />

    然后在application节点内,添加一个service,这个service是运行于后台的获取定位的服务,

            <service
                android:name="com.baidu.location.f"
                android:enabled="true"
                android:process=":remote" >
                <intent-filter>
                    <action android:name="com.baidu.location.service_v2.2" >
                    </action>
                </intent-filter>
            </service>

    最后,在application节点内,添加我们申请的百度地图API的Accesskey。

            <meta-data
                android:name="com.baidu.lbsapi.API_KEY"
                android:value="YknGmxIoPugT7YrNrG955YLS" />

    就这样,百度地图的引入就算是完成了。那么如何在代码中使用?

    打开MainActivity.java,我们需要简单重构一下代码。

    你可以使用Eclipse的重构工具,也可以手动修改代码,修改为如下:

        @Override
        protected void onCreate( Bundle savedInstanceState )
        {
            super.onCreate( savedInstanceState );
            setContentView( R.layout.activity_main );
    
            ViewUtils.inject( this );
    
            datas = new ArrayList<WeatherDataBean>();
            adapter = new WeatherAdapter( getApplicationContext(), datas );
            lstWeather.setAdapter( adapter );
    
            getWeather( "北京" );
        }
    
        private void getWeather( String city )
        {
            HttpUtils http = new HttpUtils();
    
            RequestParams params = new RequestParams();
            params.addQueryStringParameter( "location", city );
            params.addQueryStringParameter( "output", "json" );
            params.addQueryStringParameter( "ak", "YknGmxIoPugT7YrNrG955YLS" );
    
            http.send( HttpMethod.GET, "http://api.map.baidu.com/telematics/v3/weather", params, new RequestCallBack<String>()
            {
                @Override
                public void onSuccess( ResponseInfo<String> responseInfo )
                {
                    String weather = responseInfo.result;
    
                    Gson gson = new Gson();
                    data = gson.fromJson( weather, BaiduData.class );
    
                    datas.clear();
                    datas.addAll( data.getResults().get( 0 ).getWeather_data() );
                    adapter.notifyDataSetChanged();
    
                    Log.v( "onSuccess", data.toString() );
                }
    
                @Override
                public void onFailure( HttpException arg0, String arg1 )
                {
                    Log.v( "onFailure", arg1 );
                }
            } );
        }

    这里新增加了一个以城市为参数方法getWeather,做好了重构之后,我们加入百度的定位功能。

    声明两个变量:

        private LocationClient mLocationClient;
        private BDLocationListener myListener;

    添加初始化这两个变量的方法,

        private void initLocationClient()
        {
            mLocationClient = new LocationClient( getApplicationContext() ); 
            myListener = new MyLocationListener();
            LocationClientOption option = new LocationClientOption();
            option.setLocationMode( LocationMode.Hight_Accuracy );
            option.setIsNeedAddress( true );
            mLocationClient.setLocOption( option );
            mLocationClient.registerLocationListener( myListener );
        }

    我们是用到了MyLocationListener,这个类需要自定义,作为MainActivity的内部类存在,

        public class MyLocationListener implements BDLocationListener
        {
            @Override
            public void onReceiveLocation( BDLocation location )
            {
                String city = location.getCity();
                getWeather( city );
                setTitle( city + "天气" );
            }
        }

    然后,修改onCreate方法,

        protected void onCreate( Bundle savedInstanceState )
        {
            super.onCreate( savedInstanceState );
            setContentView( R.layout.activity_main );
    
            ViewUtils.inject( this );
    
            datas = new ArrayList<WeatherDataBean>();
            adapter = new WeatherAdapter( getApplicationContext(), datas );
            lstWeather.setAdapter( adapter );
    
            initLocationClient();
            mLocationClient.start();
        }

    最后,添加onStop方法,

        @Override
        protected void onStop()
        {
            super.onStop();
            mLocationClient.stop();
        }

    打完收工。

    运行吧,看看是怎样的效果,反正我的是这样:

    device-2015-01-22-161410

    是不是你所在的城市呢?

    既然看到效果了,那么稍微解释一下上面那些代码。

    首先在界面加载的时候,会调用initLocationClient方法,这个方法初始化了LocationClient和BDLocationListener,LocationClient的作用是异步获取定位,MyLocationListener则是在LocationClient获取定位后的回调方法,我们在这个回调方法中调用了获取天气的方法getWeather,并且调用setTitle方法修改了APP页面的标题为“城市名+天气”。

    整个流程堪称完美,只差一点点。

    这一点点是什么地方呢?

    就在于我们每一次获取天气之前都需要定位,而你是不会每天都换一个城市的,为此我们的程序需要优化一下。优化后的流程为:

    1. 从本地读取城市,并且同时调用百度定位

    2. 如果1中的本地城市不为空,则获取天气

    3. 如果1中百度定位的城市跟本地城市一致,就不再次获取天气;若不一致,则覆盖本地城市,并且重新获取天气

    这样做的好处有两个:

    1. 只有第一次启动APP的时候,本地城市为空,那么就是获取天气会比较快

    2. 即使更换了城市,也能准确应对

    既然整理好思路了,那么就开工吧。

    Android本地存储数据有多种方式,主要有Preference、Sqlite、File这三种,我们今天使用的是Preference这种方式。

    Preference

    Preference适合存储轻量数据,如String、Int、Boolean等类型的数据,我们所需要保存的城市数据就是一个简单的字符串,非常适合这种方式。

    在MainActivity.java 内添加两个方法,分别为存储、读取数据的方法。

        private void saveCity( String city )
        {
            SharedPreferences sharedPreferences = getSharedPreferences( "weather", Context.MODE_PRIVATE );
            Editor editor = sharedPreferences.edit();
            editor.putString( "city", city );
            editor.commit();
        }
    
        private String readCity()
        {
            SharedPreferences sharedPreferences = getSharedPreferences( "weather", Context.MODE_PRIVATE );
            return sharedPreferences.getString( "city", "" );
        }

    有些经验的程序员一眼就能看明白,Preference中是以Key/Value的形式存储数据的。

    然后修改onCreate方法,

        protected void onCreate( Bundle savedInstanceState )
        {
            super.onCreate( savedInstanceState );
            setContentView( R.layout.activity_main );
    
            ViewUtils.inject( this );
    
            datas = new ArrayList<WeatherDataBean>();
            adapter = new WeatherAdapter( getApplicationContext(), datas );
            lstWeather.setAdapter( adapter );
    
            initLocationClient();
            mLocationClient.start();
    
            String city = readCity();
            if( city != null && city.length() > 0 )
            {
                getWeather( city );
            }
        }

    这里加入了读取本地城市,并且获取天气的逻辑。

    接下来修改MyLocationListener,

        public class MyLocationListener implements BDLocationListener
        {
            @Override
            public void onReceiveLocation( BDLocation location )
            {
                String city = location.getCity();
    
                String localCity = readCity();
                if( !localCity.equals( city ) )
                {
                    saveCity( city );
                    getWeather( city );
                }
            }
        }

    这里加入了定位的城市和本地城市判断的逻辑,并且删掉了对setTitle 方法的调用.

    最后,修改getWeather方法,在方法第一行加入对setTitle的调用。

    setTitle( city + "天气" );

    打完收工,最后MainActivity.java是这个样子的:

    public class MainActivity extends Activity
    {
        @ViewInject( R.id.weather_list )
        private ListView lstWeather;
    
        private WeatherAdapter adapter;
        private BaiduData data;
    
        private List<WeatherDataBean> datas;
    
        private LocationClient mLocationClient;
        private BDLocationListener myListener;
    
        @Override
        protected void onCreate( Bundle savedInstanceState )
        {
            super.onCreate( savedInstanceState );
            setContentView( R.layout.activity_main );
    
            ViewUtils.inject( this );
    
            datas = new ArrayList<WeatherDataBean>();
            adapter = new WeatherAdapter( getApplicationContext(), datas );
            lstWeather.setAdapter( adapter );
    
            initLocationClient();
            mLocationClient.start();
    
            String city = readCity();
            if( city != null && city.length() > 0 )
            {
                getWeather( city );
            }
        }
    
        private void getWeather( String city )
        {
            setTitle( city + "天气" );
    
            HttpUtils http = new HttpUtils();
    
            RequestParams params = new RequestParams();
            params.addQueryStringParameter( "location", city );
            params.addQueryStringParameter( "output", "json" );
            params.addQueryStringParameter( "ak", "YknGmxIoPugT7YrNrG955YLS" );
    
            http.send( HttpMethod.GET, "http://api.map.baidu.com/telematics/v3/weather", params, new RequestCallBack<String>()
            {
                @Override
                public void onSuccess( ResponseInfo<String> responseInfo )
                {
                    String weather = responseInfo.result;
    
                    Gson gson = new Gson();
                    data = gson.fromJson( weather, BaiduData.class );
    
                    datas.clear();
                    datas.addAll( data.getResults().get( 0 ).getWeather_data() );
                    adapter.notifyDataSetChanged();
    
                    Log.v( "onSuccess", data.toString() );
                }
    
                @Override
                public void onFailure( HttpException arg0, String arg1 )
                {
                    Log.v( "onFailure", arg1 );
                }
            } );
        }
    
        private void initLocationClient()
        {
            mLocationClient = new LocationClient( getApplicationContext() ); // 声明LocationClient类
            myListener = new MyLocationListener();
            LocationClientOption option = new LocationClientOption();
            option.setLocationMode( LocationMode.Hight_Accuracy );
            option.setIsNeedAddress( true );
            mLocationClient.setLocOption( option );
            mLocationClient.registerLocationListener( myListener );
        }
    
        @Override
        protected void onStop()
        {
            super.onStop();
            mLocationClient.stop();
        }
    
        public class MyLocationListener implements BDLocationListener
        {
            @Override
            public void onReceiveLocation( BDLocation location )
            {
                String city = location.getCity();
    
                String localCity = readCity();
                if( !localCity.equals( city ) )
                {
                    saveCity( city );
                    getWeather( city );
                }
            }
        }
    
        private void saveCity( String city )
        {
            SharedPreferences sharedPreferences = getSharedPreferences( "weather", Context.MODE_PRIVATE );
            Editor editor = sharedPreferences.edit();
            editor.putString( "city", city );
            editor.commit();
        }
    
        private String readCity()
        {
            SharedPreferences sharedPreferences = getSharedPreferences( "weather", Context.MODE_PRIVATE );
            return sharedPreferences.getString( "city", "" );
        }
    }

    今天的主要任务就是嵌入了百度地图,重构了代码,优化了流程,最最重要的是我们学习了SharedPreferences的使用,这种保存数据方式在做APP的时候是经常会用到的,希望大家能熟练掌握。

    请注意,本文用到的key是我个人使用的,请勿将其用于任何商业用途。如果有商业需要,请联系我或者自行在百度官网申请Accesskey。

    附件是本次的工程文件,点击下载 http://pan.baidu.com/s/1jG9puYU 。

    此系列文章系本人原创,如需转载,请注明出处 www.liuzhibang.cn

  • 相关阅读:
    bzoj 1217: [HNOI2003]消防局的设立
    [USACO09FEB]庙会班车Fair Shuttle
    bzoj 1052: [HAOI2007]覆盖问题
    bzoj 1974: [Sdoi2010]代码拍卖会
    bzoj 1835: [ZJOI2010]基站选址
    bzoj 1875: [SDOI2009]HH去散步
    bzoj 3295: [Cqoi2011]动态逆序对
    bzoj 2120: 数颜色
    P1032 字串变换
    简析拓扑排序
  • 原文地址:https://www.cnblogs.com/game-over/p/4242058.html
Copyright © 2011-2022 走看看