继续昨天的学习。

昨天我们根据取得的天气数据新建了一个视图用来显示各项内容,那么今天我们就把数据显示出来吧!!!

这里我们要把数据和视图联系起来,那么就用到了适配器-Adapter,Android给我们提供了很多Adapter,这里我们用到了BaseAdapter。

 

BaseAdapter(1)

右键点击src/com.demo.weather,选择 New > Class,按照下图填写:

QQ截图20140921212540

选择[Finish]后,我们就新建了一个BaseAdapter的子类,打开 WeatherAdapter.java这个文件,来解释一下这些代码,

public class WeatherAdapter extends BaseAdapter
{

    @Override
    public int getCount()
    {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public Object getItem( int arg0 )
    {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId( int arg0 )
    {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public View getView( int arg0, View arg1, ViewGroup arg2 )
    {
        // TODO Auto-generated method stub
        return null;
    }

}

 

public int getCount()

这个方法返回ListView有几条数据,

 

public Object getItem( int arg0 )

这个方法返回当前行的数据,

 

public long getItemId( int arg0 )

这个方法返回当前行的id,

 

public View getView( int arg0, View arg1, ViewGroup arg2 )

这个方法返回当前行的视图,

那么究竟怎样把数据和视图关联起来了。

 

首先,我们需要把取得的数据转换为代码可以方便操作的形式。把json数据转换为JavaBean,我们需要用到一个gson库,可以在这里下载。 http://code.google.com/p/google-gson/

把下载回来的gson-v2.jar放到libs文件夹,然后开始我们辛苦的工作吧,将是一大段代码。

 

Gson

新建一个package包,命名为com.demo.weather.bean,在这个包下面添加4个类,BaiduData、ResultsBean、IndexBean、WeatherDataBean,内容分别是:

public class BaiduData
{
    private int error;
    private String status;
    private String date;
    private List<ResultsBean> results;

    public int getError()
    {
        return error;
    }
    public void setError( int error )
    {
        this.error = error;
    }
    public String getStatus()
    {
        return status;
    }
    public void setStatus( String status )
    {
        this.status = status;
    }
    public String getDate()
    {
        return date;
    }
    public void setDate( String date )
    {
        this.date = date;
    }
    public List<ResultsBean> getResults()
    {
        return results;
    }
    public void setResults( List<ResultsBean> results )
    {
        this.results = results;
    }
}

 

public class ResultsBean
{
    private String currentCity;
    private String pm25;
    private List<IndexBean> index;
    private List<WeatherDataBean> weather_data;

    public String getCurrentCity()
    {
        return currentCity;
    }
    public void setCurrentCity( String currentCity )
    {
        this.currentCity = currentCity;
    }
    public String getPm25()
    {
        return pm25;
    }
    public void setPm25( String pm25 )
    {
        this.pm25 = pm25;
    }
    public List<IndexBean> getIndex()
    {
        return index;
    }
    public void setIndex( List<IndexBean> index )
    {
        this.index = index;
    }
    public List<WeatherDataBean> getWeather_data()
    {
        return weather_data;
    }
    public void setWeather_data( List<WeatherDataBean> weather_data )
    {
        this.weather_data = weather_data;
    }
}

 

public class IndexBean
{
    private String title;
    private String zs;
    private String tipt;
    private String des;

    public String getTitle()
    {
        return title;
    }
    public void setTitle( String title )
    {
        this.title = title;
    }
    public String getZs()
    {
        return zs;
    }
    public void setZs( String zs )
    {
        this.zs = zs;
    }
    public String getTipt()
    {
        return tipt;
    }
    public void setTipt( String tipt )
    {
        this.tipt = tipt;
    }
    public String getDes()
    {
        return des;
    }
    public void setDes( String des )
    {
        this.des = des;
    }
}

 

public class WeatherDataBean
{
    private String date;
    private String dayPictureUrl;
    private String nightPictureUrl;
    private String weather;
    private String wind;
    private String temperature;

    public String getDate()
    {
        return date;
    }
    public void setDate( String date )
    {
        this.date = date;
    }
    public String getDayPictureUrl()
    {
        return dayPictureUrl;
    }
    public void setDayPictureUrl( String dayPictureUrl )
    {
        this.dayPictureUrl = dayPictureUrl;
    }
    public String getNightPictureUrl()
    {
        return nightPictureUrl;
    }
    public void setNightPictureUrl( String nightPictureUrl )
    {
        this.nightPictureUrl = nightPictureUrl;
    }
    public String getWeather()
    {
        return weather;
    }
    public void setWeather( String weather )
    {
        this.weather = weather;
    }
    public String getWind()
    {
        return wind;
    }
    public void setWind( String wind )
    {
        this.wind = wind;
    }
    public String getTemperature()
    {
        return temperature;
    }
    public void setTemperature( String temperature )
    {
        this.temperature = temperature;
    }
}

 

这4个JavaBean承载了json格式的字符串转换后的对象。

 

然后,打开MainActivity.java文件,这个文件还有一个小红叉,那是我们之前删掉了一个文本后没有及时修改代码造成的后果。不用客气,把它删掉。

修改http.send方法为以下内容:

        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();
                BaiduData data = gson.fromJson( weather, BaiduData.class );

                Log.v( "onFailure", data.toString() );
            }

            @Override
            public void onFailure( HttpException arg0, String arg1 )
            {
                Log.v( "onFailure", arg1 );
            }
        } );

 

到这里,先搞一段落,来解释一下这么多的代码。

虽然代码很多,但是都很简单,BaiduData、ResultsBean、IndexBean、WeatherDataBean这4个类是根据gson的要求,结合百度天气API的返回数据做成的标准JavaBean。

                Gson gson = new Gson();
                BaiduData data = gson.fromJson( weather, BaiduData.class );

这两行是核心功能,把Json格式的字符串转换为了我们做成的BaiduData这个JavaBean。

 

BaseAdapter(2)

既然已经把数据格式化为JavaBean了,剩下的工作就简单多了。

 

修改WeatherAdapter使得数据和视图关联,

public class WeatherAdapter extends BaseAdapter
{
    private List<WeatherDataBean> weathers;
    private LayoutInflater inflater;
    private BitmapUtils bitmapUtils;

    public WeatherAdapter( Context context, List<WeatherDataBean> weathers )
    {
        this.weathers = weathers;
        inflater = LayoutInflater.from( context );
        bitmapUtils = new BitmapUtils( context );
    }

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

    @Override
    public Object getItem( int position )
    {
        return weathers.get( position );
    }

    @Override
    public long getItemId( int position )
    {
        return position;
    }

    @Override
    public View getView( int position, View convertView, ViewGroup parent )
    {
        convertView = inflater.inflate( R.layout.item_weather, null );

        TextView txtDate = (TextView)convertView.findViewById( R.id.item_date );
        TextView txtWeather = (TextView)convertView.findViewById( R.id.item_weather );
        TextView txtWind = (TextView)convertView.findViewById( R.id.item_wind );
        TextView txtTemperature = (TextView)convertView.findViewById( R.id.item_temperature );
        ImageView imgTemperature = (ImageView)convertView.findViewById( R.id.item_picture );

        WeatherDataBean bean = (WeatherDataBean)getItem( position );

        txtDate.setText( bean.getDate() );
        txtWeather.setText( bean.getWeather() );
        txtWind.setText( bean.getWind() );
        txtTemperature.setText( bean.getTemperature() );

        bitmapUtils.display( imgTemperature, bean.getDayPictureUrl() );

        return convertView;
    }

}

 

这里我们使用了LayoutInflater来载入昨天做成的item_weather界面,使用了BitmapUtils来加载网络图片。虽然是大段代码,但是道理很简单,把对应的数据显示到对应的项目。

 

然后,在MainActivity.java里添加对ListView以及我们之前建好的WeatherAdapter类的引用,并且将ListView、WeatherAdapter、BaiduData三个对象关联起来,

public class MainActivity extends Activity
{
    @ViewInject( R.id.weather_list )
    private ListView lstWeather;

    private WeatherAdapter adapter;
    private BaiduData data;

    private List<WeatherDataBean> datas;

    @Override
    protected void onCreate( Bundle savedInstanceState )
    {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.activity_main );

        ViewUtils.inject( this );

        HttpUtils http = new HttpUtils();

        datas = new ArrayList<WeatherDataBean>();
        adapter = new WeatherAdapter( getApplicationContext(), datas );
        lstWeather.setAdapter( adapter );

        RequestParams params = new RequestParams();
        params.addQueryStringParameter( "location", "北京" );
        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 );
            }
        } );
    }
}

打完收工。

 

最终的效果如下:

device-2015-01-20-171134

 

同志们,很有成就感了吧!!!

 

不要得意,这只是把数据简单的显示出来而已,并且只能是帝都北京的数据,如果你不在北京,这根本对你一点用处都没有啊。

嗯嗯,今天就到这儿吧,已经足够多了,好学的你肯定已经在查找更多关于Adapter、ListView的知识了,这里我就不做介绍了,建议大家经常百度。

 

休闲一下,说点废话。

本人从事IT行业10余年,从最初级的菜鸟程序员开始,一步一步成长,见过形形色色的程序员,从个人的角度把程序员分成这么几个级别:

1. 无脑

这个指的是一遇到问题就问别人的同志,自己也不思考,也不求上进,混一天算一天。这种类型是极少数的,我也只是听说过,都是传说中的人物。

2. 菜鸟

这种类型的程序员非常多,通常是接触技术时间不长的朋友。这部分通常是没有网络就不能工作了,经常在论坛里查找资料,下载别人代码拿来使用,键盘上的Ctrl、C、V键都磨光了。

3. 小牛

这种类型多见于技术负责人、技术总监这样的职位,要想做到小牛这一步,需要对技术有比较深的了解,能够从无到有进行设计的。在各种开源社区,这部分人通常会比较活跃,菜鸟们大都使用小牛们的劳动成果。

4. 大牛

这种类型的人已经非常少了,我只见过那么几位,都是各大公司CTO之类的。说说其中一位,他从无到有设计了公司的云计算方案,从硬件的基础设施到软件层面,再到用户层面,这位大牛都有深入的掌握。

5. 传说

鄙人只能在各种新闻、书籍中才能见到了。个人认为这部分人的技术已经不是我们可以评判的了,他们的思想、影响力根本不是我等可以企及的。

 

各位亲,你是哪个级别的?

 

附件是本次的工程文件,点击下载

 

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

经过第二天的学习,我们正确的调用了百度天气API,将天气信息显示到了界面上,做到这一步,我们的工作就算是完成1%了,剩下99%的工作就需要不断的润色这个未成形的APP了。

最首要的就是,我们要把那么一大堆字符转换为普通用户可以轻松理解的界面,那么我们来学习一下Android里面的界面布局。

打开res/layout/activity_main.xml文件,切换到Layouts选项卡,可以看到里面有许多项目,GridLayout、LinearLayout、RelativeLayout等,这些都代表什么类型的布局呢?

QQ截图20140921162822

理论知识

总体来说,Android界面布局分为5中,分别为LinearLayout(线性布局)、RelativeLayout(相对布局)、FrameLayout(框架布局)、TableLayout(表格布局)、GridLayout(网格布局),下面逐一简单介绍一下。

LinearLayout(线性布局)

LinearLayout使得布局内部的元素以水平(horizontal)或者垂直(vertical)的方式排成一行,

<LinearLayout 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:orientation="horizontal" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第一个文本" />
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第二个文本" />

</LinearLayout>

 

其中,android:orientation指定布局内部元素的排列方式,如果没有此项设置,默认为水平排列。

设置好排列方式之后的效果分别如下:

QQ截图20140921164824QQ截图20140921165036

 

RelativeLayout(相对布局)

RelativeLayout使得布局内部的元素以相对于容器、其他元素的位置排列,

<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" >

    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="第一个文本" />

    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/text1"
        android:layout_toRightOf="@id/text1"
        android:text="第二个文本" />

</RelativeLayout>

 

这个布局定义了第一个文本位于布局的左上角,第二个文本在第一个文本的右下。

QQ截图20140921165837

FrameLayout(框架布局)

FrameLayout使得布局内部的元素按照层次堆叠在左上角,后添加的元素会覆盖前面的元素。

<FrameLayout 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" >

    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="60sp"
        android:background="#00ff00"
        android:text="第一个文本" />

    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:textSize="40sp"
        android:layout_height="wrap_content"
        android:background="#ff00ff"
        android:text="第二个文本" />

</FrameLayout>

 

这样第二个文本会覆盖在第一个文本的上面,

QQ截图20140921170506

TableLayout(表格布局)

TableLayout使得布局内部的元素以行和列的形式排列,每一行都是一个TableRow或者一个普通的View,

<TableLayout 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:stretchColumns="1">

    <TableRow>
        <TextView
            android:layout_column="1"
            android:text="Open..."
            android:padding="3dip" />
        <TextView
            android:text="Ctrl-O"
            android:gravity="right"
            android:padding="3dip" />
    </TableRow>

    <TableRow>
        <TextView
            android:layout_column="1"
            android:text="Save..."
            android:padding="3dip" />
        <TextView
            android:text="Ctrl-S"
            android:gravity="right"
            android:padding="3dip" />
    </TableRow>

    <View
        android:layout_height="2dip"
        android:background="#FF909090" />

    <TableRow>
        <TextView
            android:layout_column="1"
            android:text="Quit"
            android:padding="3dip" />
    </TableRow>

</TableLayout>

 

这个布局有四行,1、2、4行是TableRow,各有数目不同的文本,第3行是一个普通的View,

QQ截图20140921172116

GridLayout(网格布局)

GridLayout使得布局内部的元素以行、列、单元格的形式排列,

<?xml version="1.0" encoding="utf-8"?>  
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"  
    android:orientation="horizontal"  
    android:rowCount="5"  
    android:columnCount="4" >  
  <Button  
        android:text="1"/>  
  <Button  
        android:text="2"/>  
  <Button  
        android:text="3"/>  
  <Button  
        android:text="/"/>  
  <Button  
        android:text="4"/>  
  <Button  
        android:text="5"/>  
  <Button  
        android:text="6"/>  
  <Button  
        android:text="×"/>  
  <Button  
        android:text="7"/>  
  <Button  
        android:text="8"/>  
  <Button  
        android:text="9"/>  
   <Button  
        android:text="-"/>  
   <Button  
        android:layout_columnSpan="2"  
        android:layout_gravity="fill"  
        android:text="0"/>  
   <Button  
        android:text="."/>  
   <Button  
        android:layout_rowSpan="2"  
        android:layout_gravity="fill"  
        android:text="+"/>  
   <Button  
        android:layout_columnSpan="3"  
        android:layout_gravity="fill"  
        android:text="="/>   
</GridLayout>

 

这里定义了一个简单的计算器布局,

QQ截图20140921172904

 

其他布局

除了以上5种主要的布局,还有一些第三方的布局,可以让你方便的实现一些比较酷炫的效果,例如DrawerLayout(左滑弹出菜单)、SwipeBackLayout(左滑返回)等,这些知识需要有一定的开发经验之后慢慢摸索。

小结

以上是简单介绍了一下各种布局的使用方式,具体各个布局还有很多的属性,活用这些属性才会制作出实用的界面,这些属性要靠大家在不断的学习中慢慢掌握。

在所有的布局里面,我这里推荐大家使用RelativeLayout。如果使用其他布局,可能需要嵌套比较多的层级才可以实现的界面,通常使用RelativeLayout会比较方便,而如果层级较多,对于界面的展示会需要耗费比较多的内存,所有我这里推荐使用RelativeLayout。

 

好了,大家辛苦了,先休息一下吧,下面我们就要使用RelativeLayout来做我们的第一个界面了。

 

天气界面

让我们回到我们的项目,打开res/layout/activity_main.xml文件,删掉TextView,添加一个新的控件-ListView。

QQ截图20140921185030

 

然后切换到代码模式,确认一下ListView的属性,

    <ListView
        android:id="@+id/weather_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" >
    </ListView>

 

这里的属性说明的是这个ListView宽度撑满界面,高度自适应,水平居中并且垂直居中,它的id是weather_list,大家还记得id的作用吧,它使得这个控件在代码中可以被找到并使用。

话说这个ListView是干什么用的?

当然是显示天气了。还以北京的天气为例,http://api.map.baidu.com/telematics/v3/weather?location=%E5%8C%97%E4%BA%AC&output=json&ak=YknGmxIoPugT7YrNrG955YLS, 这个链接返回的数据是:

{
error: 0,
status: "success",
date: "2015-01-19",
results: [
{
currentCity: "北京",
pm25: "80",
index: [
{
title: "穿衣",
zs: "冷",
tipt: "穿衣指数",
des: "天气冷,建议着棉服、羽绒服、皮夹克加羊毛衫等冬季服装。年老体弱者宜着厚棉衣、冬大衣或厚羽绒服。"
},
{
title: "洗车",
zs: "较适宜",
tipt: "洗车指数",
des: "较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。"
},
{
title: "旅游",
zs: "适宜",
tipt: "旅游指数",
des: "天气较好,同时又有微风伴您一路同行。虽会让人感觉有点凉,但仍适宜旅游,可不要错过机会呦!"
},
{
title: "感冒",
zs: "少发",
tipt: "感冒指数",
des: "各项气象条件适宜,无明显降温过程,发生感冒机率较低。"
},
{
title: "运动",
zs: "较适宜",
tipt: "运动指数",
des: "天气较好,但考虑气温较低,推荐您进行室内运动,若户外适当增减衣物并注意防晒。"
},
{
title: "紫外线强度",
zs: "最弱",
tipt: "紫外线强度指数",
des: "属弱紫外线辐射天气,无需特别防护。若长期在户外,建议涂擦SPF在8-12之间的防晒护肤品。"
}
],
weather_data: [
{
date: "周一 01月19日 (实时:3℃)",
dayPictureUrl: "http://api.map.baidu.com/images/weather/day/qing.png",
nightPictureUrl: "http://api.map.baidu.com/images/weather/night/qing.png",
weather: "晴",
wind: "微风",
temperature: "-5℃"
},
{
date: "周二",
dayPictureUrl: "http://api.map.baidu.com/images/weather/day/duoyun.png",
nightPictureUrl: "http://api.map.baidu.com/images/weather/night/duoyun.png",
weather: "多云",
wind: "微风",
temperature: "5 ~ -2℃"
},
{
date: "周三",
dayPictureUrl: "http://api.map.baidu.com/images/weather/day/qing.png",
nightPictureUrl: "http://api.map.baidu.com/images/weather/night/qing.png",
weather: "晴",
wind: "北风3-4级",
temperature: "5 ~ -6℃"
},
{
date: "周四",
dayPictureUrl: "http://api.map.baidu.com/images/weather/day/qing.png",
nightPictureUrl: "http://api.map.baidu.com/images/weather/night/qing.png",
weather: "晴",
wind: "微风",
temperature: "6 ~ -5℃"
}
]
}
]
}

这是json格式的数据,其中[weather_data]这个节点就是当前以及接下来4天的天气,一共是5条数据,这样标准的列表数据当然是使用ListView控件来显示了。

那么,如何进行呢?

赵本山老师教过我们,总共分三步,

1. 取得数据

2. 做成界面

3. 把数据显示到界面上

那么,数据已经取得了,下面就进行第二步,做成界面。

ListView

如何使用ListView?在Android的设计中,这里就是一个标准的代码分离的方案,ListView作为一个容器使用,而其中的每一项单独使用另外的View来实现,那么,具体来说我们需要做些什么?

不要着急,慢慢来。

邮件点击res/layout目录,选择New > Android XML File,在弹出框中按照下图所示进行填写,

QQ截图20140921203413

然后点击Finish,就切换到了我们新建的这个视图了,这个视图将定义ListView中每一项都显示什么内容。根据百度的数据,我们的这个天气预报APP可以显示日期、天气、风、温度以及两个分别代表白天晚上的天气图片,那么我们就可以开始行动了,先添加4个TextView和1个ImageView,位置可以随便放置。需要注意的是在添加ImageView的时候,会弹出选择图片资源的对话框,我们就选中默认的ic_launcher就好了。

这些做好之后,看看我们的界面是什么样子。不管怎么说,我的是这样子的:

QQ截图20140921204537

很那看是不是,还是那句话,不着急,我们来调整一下。

选中左上角的TextView,然后注意图中红框部分,我们将在这里设置它的属性,包括宽度、位置、字体等,大家练习一下吧,试着设置一下各个项目,看看都会有什么反应。

 

嗯,先来看看我调整后的界面吧。

QQ截图20140921205841

说不上好看,也算是比较标准的列表项目了。分享一下我的代码吧:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp" >

    <TextView
        android:id="@+id/item_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="日期"
        android:textColor="#000000"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/item_weather"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/item_date"
        android:layout_marginTop="5dp"
        android:text="天气"
        android:textColor="#000000"
        android:textSize="14sp" />

    <TextView
        android:id="@+id/item_wind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/item_date"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="5dp"
        android:layout_toRightOf="@id/item_weather"
        android:text="风"
        android:textColor="#000000"
        android:textSize="14sp" />

    <TextView
        android:id="@+id/item_temperature"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/item_date"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="5dp"
        android:layout_toRightOf="@id/item_wind"
        android:text="温度"
        android:textColor="#000000"
        android:textSize="14sp" />

    <ImageView
        android:id="@+id/item_picture"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:src="@drawable/ic_launcher" />

</RelativeLayout>

 

你可以直接使用我的设置,这样很方便。   ^_^

嗯,到这里,三步里面的第二步也完成了,好辛苦啊,休息休息。

通过今天的折腾,我们的界面又变成不显示任何内容的了,不要担心,我们明天继续。

 

附件是本次的工程文件,点击下载

 

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

继续我们的学习。

相信我,第一天的工作是最为重要的,通过这些工作,我们把开发安卓所必须的环境、基础条件都配置好了,相信肯定遇到了很多问题,不过,根据我的经验,您会很快解决这些问题的。在第一天的最后,我们终于运行了第一个应用->“Hello, world”。

理论知识

下面我们学习一些理论知识,了解一下安卓系统的架构、组件,有了一些基础知识,才不会感觉迷惑。

先看下整个项目的目录,每个目录都有特定的作用,分别如下:

  • src目录,存放源代码文件。
  • gen目录,由ADT插件自动生成的R.java文件。
  • assets目录,存放资源文件目录。此目录的文件不会在R.java中生成资源ID,不会被编译为二进制,必须使用/assets开始的相对路径按照文件的方式进行访问,可以使用AssetManager 结合其他类进行访问。
  • res目录,存放资源文件目录,这里面的每个文件或值都会在R.java中生成一个ID(变量);res/drawable-xxxx是存放图片的目录;res/layout是放置布局文件(xml文件)的目录,每个Activity对应一个XML文件;res/values是放置存储值的文件(xml)的目录;res/values/strings.xml 存放键值对,一般用在程序的多语言版本切换(多个文件,键一样,值不同);res/values/dimens.xml 尺寸;res/values/styles.xml 样式
  • AndroidManifest.xml是整个应用程序的配置文件,储存一些 包名,版本号,程序图标,程序标签等。
  • project.properties,由ADT插件自动生成,不能修改(修改将被删除)。

 

对于项目结构有了初步的了解之后,我们就可以有目的的开始我们的工作了。接下来的10天,我们将一步一步实现一个完整的天气预报应用,请注意:是完整的,而不只是Demo。

我们最终的页面效果如下所示:

device-2015-01-18-130830

 

任务分解

不要被吓到,不管现在看起来多么复杂,这终究会从我们的手中实现。为了实现这样的一个应用,我们需要分为一个一个小项目,这样看起来就不是那么庞然大物,我们心里底气也足了。

如果您曾经做过项目管理相关工作的话,那么对于WBS(工作分解结构)一定很熟悉了,我们的应用规模不算大,可以分解为如下小项目:

1. 学习调用HTTP接口,将返回的JSON数据封装为Java类,并且最终将天气数据展示到页面上

2. 学习使用百度地图SDK定位当前位置,并将当前位置信息保存为本地数据

3. 如果没有网络,我们就没办法查看天气了吗?这当然是有问题的,我们要把天气数据保存到本地数据库,并且默认显示本地数据

4. 美化UI

在这短短的10天内,我们要把这些工作都做完,不要犯怵,Follow me!!!

千里之行始于足下

新建一个工程,Application Name填Weather,Package Name填com.demo.weather,SDK各个项目的选择如下:

QQ截图20140910225041

 

选择好之后,就一路点击【Next】直到我们的项目建好为止,建好的项目应该是这样子的:

QQ截图20140910225349

 

打开res/layout/activity_main.xml,在Eclipse中应该是这个样子的:

QQ截图20140910225709

 

注意视图的下方有两个Tab选项卡,【Graphical  Layout】是图形视图,【activity_main.xml】是代码视图,我们切换为代码视图,在TextView处添加一行代码,

android:id="@+id/weather"

这样,我们就可以在代码中使用findViewById方法找到这个TextView控件,不过,为了代码的美观,我们将使用另外的办法。

使用第三方组件

大家都知道,Android是开源的,所以就有很多具有奉献精神的牛人把自己的经验、收获分享给大家,这就是很多很多的开源代码、组件、框架。

在这里我们引入第一个开源组件——xUtils,可以在https://github.com/wyouflf/xUtils这里查看它的详细说明。

首先,下载jar包,并且导入到我们的工程里面,说起来麻烦,做起来那是相当简单。下载地址:https://github.com/wyouflf/xUtils/blob/master/xUtils-2.6.11.jar,然后将下载下来的文件放到工程项目的libs文件夹就可以了。

如何在项目中使用呢?

如果大家懒得看xUtils的文档,那就跟着我一步一步做就好了。

打开src目录下,com.demo.weather的MainActivity文件,添加一个变量,可以命名为txtWeather。

@ViewInject( R.id.weather )
private TextView txtWeather;

这样,我们就可以在代码中使用TextView这个控件了。

接下来,我们看一下onCreate方法,这个方法现在只有两行代码,

super.onCreate( savedInstanceState );
setContentView( R.layout.activity_main );

 

其中第一行,调用父类的onCreate方法进行界面的绘制,第二行就是加载界面,这两行代码在所以的Activity的子类都是需要调用的,除非你不在界面显示任何内容。

onCreate方法有一个参数savedInstanceState,关于这个我们稍后细说,先说第二行代码

setContentView( R.layout.activity_main );

R.layout.activity_main指向了res/layout/activity_main.xml这个文件,这样界面就知道应该加载这个界面文件了。可能大家都Activity是什么还有些疑惑,不要紧,这些理论知识我们明天再说,今天我们的任务就是把天气数据显示到界面上。当然,我们自己是不知道天气预报数据的,不过万能的互联网什么都有,百度就提供了这方面的数据。

官方文档:http://developer.baidu.com/map/index.php?title=car/api/weather,

一个例子:http://api.map.baidu.com/telematics/v3/weather?location=%E5%8C%97%E4%BA%AC&output=json&ak=YknGmxIoPugT7YrNrG955YLS

好了,万事俱备,只欠代码。如何把天气显示到界面上,总共分三步:

1. 在界面上放置一个TextView用于显示文字,这个我们已经完成了。

2. 调用百度地图的API,获取天气数据,这个我们接下来就要做。

3. 把数据显示到界面上。

松了一口气,喝杯茶,休息十分钟吧,接下来会有大段的代码等着你来完成。

 

休息好了吧,我们马上开工。

在onCreate方法的setContentView下面添加以下代码,

        ViewUtils.inject( this );

        HttpUtils http = new HttpUtils();

        RequestParams params = new RequestParams();
        params.addQueryStringParameter( "location", "北京" );
        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;
                txtWeather.setText( weather );
            }

            @Override
            public void onFailure( HttpException arg0, String arg1 )
            {
                String weather = arg1;
                txtWeather.setText( weather );
            }
        } );

并且删除onCreateOptionsMenu方法。

保存吧,一大段的代码,一大片的红叉,呵呵,不着急,慢慢来,那是因为我们使用了第三方组件的原因,一项一项把缺失的引用添加进来就可以了。如果你嫌麻烦,那么复制这几行代码吧。

import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.ViewUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;
import com.lidroid.xutils.view.annotation.ViewInject;

 

这下大家满足了吧,一切看起来都是那么的顺利和完美,来,运行程序。

你看到的可能是这样的内容:

java.io.IOException: Permission denied (missing INTERNET permission?)

为什么?为什么?为什么?

辛辛苦苦,XX都X了,你就让我看这个。

不着急,不着急,上面写得很明白,没有访问网络的权限,那么,在项目里面找到AndroidManifest.xml这个文件,添加一行代码即可。

<uses-permission android:name="android.permission.INTERNET" />

把这行代码加到 <application 的前面就可以了,好了,一切都OK了。运行吧。

这下界面上显示的就是一大堆天气的数据了。

device-2015-01-18-131401

 

如果显示的还不正确,那么请仔细检查一下是否有遗漏的代码,是否真的可以连上网络。

如果您可以正确的显示上面那一大堆字符,并且能正确理解那一大堆字符的意义,并且对于界面什么的也没有要求的话,那么我们的天气预报APP就可以给自己独家使用了。很有成就感了是不是,不过,这样的应用除了自己谁会用呢?恐怕连自己也是看都不想看吧。

如果您有更要的要求,那么,明天我们继续。

 

附件是本次的工程文件,点击下载

说明1:本系列教程仅针对新手入门,高手勿入!

说明2:本系列教程均不考虑安卓版本低于4.0的情况。

说明3:本系列教程假定您了解一些编程的基础知识,对于Java语言略懂即可。

 

说点废话

从什么时候说起呢,应该是很久以前的事情了。

2008年的早春,因为工作的原因在日本工作了一个月,当我和同事们在XXX闲逛的时候,发现了以前从未见过的电子设备,一款是大屏幕(当时可以称得上巨屏了)的手机,一款是超大容量(80G)的MP3,对了,也许聪明的你已经猜到了,一个是iPhone 1,一个是iPod Classic,

于是,一个崭新的时代开启了,当然,我们都是旁观者,真正的主角是Apple和Google。

 

真正的开始其实是2007年,在这一年,Apple和Google先后发布了iPhone1以及Android操作系统,从此,一发不可收拾,iPhone以每年一代产品的速度迭代,Android则先后发布了许多成功的、失败的版本,具体的数字就不列举了,只要大家知道智能的才是未来的,作为程序员,更要时刻瞄准最新的技术。

 

比如Google Glass

 

1383875416091.jpg

 

废话不多说了,我们言归正传,本教程的目标不是仅仅让大家学会编写一些事例,更会让大家制作一个完整的可以运营的应用,在这个过程中,你会慢慢掌握Android开发中必备的知识,以及如何来解决遇到的问题,最终,你会发挥自己的聪明才智,开始制作自己专属的应用。

Come on, baby!

 

工欲善其事,必先利其器

移动互联网的时代,多少创业者一鸣惊人,升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰。相信我,这一切都不是梦,但是千里之行始于足下,首先你要具备以下软硬件:

1. 至少一台设备

国内买手机,选择何其多,三星、Sony、LG、Moto甚至Nokia这些国际大厂的品牌,到HTC、小米、魅族、中华酷联这些国内知名厂商,甚至金立、大黄蜂、小辣椒这些山寨货,高中低档任君选择。不过对于我们开发人员来说,最好的选择必须是Google的亲儿子,重点推荐Nexus 4,或者即将发布的Google的下一代旗舰级。

2. 一台电脑

相比较于iOS开发对于电脑的要求,Android开发简直太人性了。不管你是Windows、Linux、Mac,只要安装了Java环境,都可以进行Android开发。

本文假定大家使用的是Windows环境,以下的操作都是基于Win8系统的,如果你的操作系统不是Windows,那么安装Java之类的我想是更不在话下了。

3. 软件环境

首先安装Java环境,请移步 http://www.oracle.com/technetwork/java/javase/downloads/index.html 下载。

其次,Google推荐使用Eclipse+ADT的组合,请移步 http://developer.android.com/sdk/index.html 下载。

别告诉我你上不去这个网站,请自己想办法。

 

 

开启Android之旅

安装好以上环境后,解压下载的adt-bundle-windows…..zip文件,打开eclipse,先确认Android环境是否完备。

依次选择菜单 File >> New >> Android Application Project,

20140818213524

其中Application Name填写demo后,会自动生成Project Name和 Package Name,我们保留默认值就好了,然后选择Minimum Required SDK为API14,我们只针对4.0以上的版本进行开发。

选择好之后,请一路点击[Next],直到最后一步,点击[Finish],我们的第一个应用项目就搭建好了。

连上你的手机之后,在项目的根节点右键选择[Run As] >> [Android Application],会弹出设备选择框,

20140818215401

看到了吧,我的手机是小米3。

如果没出现设备的话,请依次检查USB线是否连接、驱动是否安装、手机是否已经开启[USB调试],一切正常的话,点击[OK],程序就运行到手机上了。

0818_22_01_01

 

好了,第一天就到这儿吧,万事开头难,我相信在配置环境的过程中,大家都遇到了不少问题,请利用好百度、Google这些工具。

明天开始,我们即将有一个全新的目标。

最近在琢磨程序员到底路在何方,经过不断的自虐和代入,终于在迷雾森林中得图一张,看之豁然开朗。独乐乐不如众乐乐,share了:

a2094_005WTVurjw1eoa928kgmej30hy0jnwhq

术语表

图1中使用了很多术语,这里先做解释,只有我们大家都说同一种语言,沟通才会顺畅。

程序员:撰写代码,生产软件,辅助提高社会生产率的脑力劳动者。据说喝的是咖啡,抽的是烟,产的是代码。他们是计算机诞生后才逐渐兴起的一个群体,鱼龙混杂,有高飞天上的白富美,也有低到尘埃里的矮矬穷,总之虽一类而九流具足。

初级工程师:入门程序员,怀揣着IT行业多金的遐想进入了IT江湖,开始了练级打怪求升级的游戏之路。

中级工程师:经过几年的打拼,有一定的拷贝、粘贴功底,掌握了太祖长拳或罗汉掌之类的一技之长,打字速度变快了,双眼变得稍稍有些迷人了,对零壹世界有了比初级工程师更深刻的认识。

高级工程师:拷贝、粘贴之术出神入化,又习得搭积木和沙滩上盖大楼的绝技,还能像江湖郎中一样给病入膏肓的代码开药了。

架构师:坚信技术可以让人牛X,抵制了各种旁门左道的火辣诱惑,闭关多年,终于一生二、二生三、三生万物了,能够坐而论道、指手画脚了,觉得自己形神具备有仙人之资,偶尔来个仙人指路挺爽。

技术专家:看过各种江湖流派,最终在某条羊肠小道之上月黑风高之夜顿悟辟邪剑法,从而成为一代旁门高手,在自己的领域里无人能及。

CTO:史上最强的技术流?不一定。不过有一点高度是肯定的:会当凌绝顶,一览众山小。正统的CTO专门研究各种武技,寻求能在未来的江湖中克敌制胜的秘辛。国内江湖乱象纷呈,很多CTO其实在打杂做管理。

小组组长:这并不是一个正式的头衔,在《江湖异闻录》中,小组组长被掌门委以突袭带头人的角色,只因为他有带头大哥的潜力,能激发大家的战斗力。虽然没有掌握绩效考评之类的绝杀技,不过也是通往管理之路的必经过程。

项目组长:管的事儿有点儿多了,要带人,要带项目,要和产品经理搞好关系,通常也得和小分队的成员不分你我,总之什么都干,干的是项目经理的活,只是没有名分。没关系,等带好一个项目,又有项目经理的缺时就可以顶上去了。

项目经理:这是一个正式的打杂的,终于有了名分了。

高级项目经理:又叫项目群经理。他搬了把凳子以便让自己站得更高,能够看清楚纷乱的江湖里多个项目的情况,通常需要协调这个协调那个,找项目经理谈谈话,抚慰一下项目经理或项目组长委屈的心,有时也会被来自上面的压力压得喘不过气来。

部门(项目)总监:So,不知道要说什么了,开始管各种事儿了,评估项目开发过程,拟定考评、绩效、职级等各种制度,或者今天跑这个项目聊聊天,明天跑那个项目聊聊天,后者自己左右互搏和自己聊聊天,看起来闲人一个。

就这么多吧,其它的也不想说了。因为我们要讨论的是程序员的出路……

程序员的路在何方

图1中框起来的,是程序员的主旋律。

程序员,专业人士也,与瓦工、木匠、发型师、保洁员等类似,不过是社会万千分工之一种,没什么高大上,也没什么矮矬穷,只不过时代大潮中被滚滚洪流裹夹着前进的一群人而已,所谓泯然众人矣,就是说的这个。

So,该说什么啦?

你怎么混进来的

不忘初衷。

不忘初心。

你是不是忘了当初为什么要干这个?

那就想想吧。有好处。

有的人是为了程序员的高薪

有的人是想要一份体面稳定的工作而已,别出差

有的人是过来打酱油的早抱定了过两年就走的心

有的人想了解这个世界,试试看自己合不合适

有的人就喜欢计算机的世界,如鱼得水

有的人觉得这个行当既专业又神秘,感觉倍儿棒

有的人喜欢挑战,因为软件开发每一刻都有战斗的感觉,各种问题纷至沓来

有的人就喜欢不断学习新技术,为技术而生,而没有哪个行业像这个一样时刻都要学习

有的人喜欢这个行当的成就感,持续不断的小刺激总让人高潮不断

有的人渴望有自己的软件作品

有的人想用软件改变世界

有的人觉得这是一片净土,罕见尔虞我诈,不必江海寄余生

有的人觉得这行门槛低,谁都可以来搞两下

有的人是来发动战争的,攻破别人的防线感觉很爽

有的人是冲着 IT 界牛人半数都出柜这一点来的

……

总之各种理由都有,你也一定有自己的那一个。对吧,你自己的。

将来去哪儿

迪克牛仔的《三万英尺》:

要飞向哪里 能飞向哪里

愚笨的问题

我浮在天空里

自由的很无力

前几天在朋友家翻看米兰昆德拉的《不能承受的生命之轻》,里面开篇对轻与重的辩论,很有意思,好像和我们也有一点关系,感兴趣的可以读读,这本书是倒退十来年那个时候小资必读。

你今天的选择,决定了明天的路。

那些来打酱油的,明天就走了。比如我原来有个同事,干了一阵子,来找我辞职,说准备回家搞民间金融去了。后来还在QQ上联系过我,据说搞得还不错,问我要不要投资。

有些人听说IT行业薪资高,巴巴地进来了,可是干了两三年,工资还是三两千,只好失望的走了。其实除非你有经天纬地之才,没有一开始就高薪的道理。先做事,后有钱。先想钱,钱难来。做程序员搞开发大抵是酱紫的。听说有个哥们跳到了华为,天天晚上十一二点的搞,有一天他终于不慎抱恙,晚上九点多回去了,被整个组的人鄙视;可是华为熬过三年,钱多多的,年终奖和分红抵得上你一年的工资。关键是,你熬得住吗?你媳妇熬得住吗?

有一段时间我觉得心不够静,买了几本佛经想受点熏陶,读了《金刚经》、《坛经》、《心经》、《地藏经》,不过都没读完。后来在一个同事的工位上看到她贴了一个即时贴:

“观自在菩萨,行深般若波罗蜜多时……”

原来心不净的人可真多呀,好吧,我不是一个人在战斗,太欣慰了。

我看到女同事贴的这段《心经》中的文字没多久,她离开了公司。再后来我到书店闲逛,发现摆在显眼处的都是什么这个禅师、那个道长、某个灵修、西方冥想者出的拯救大家心灵的菩提书,也有很多国内的心理作家写的鸡汤,多得很呢真是。我这才意识到,原来我们都有病,药不能停啊。

扯远了吧。

我想说的是,作为程序员,心态决定你的将来。你自己怎么看待你所从事的工作,你是享受它、厌烦它、无所谓、爱恨交加……这些决定了你将在这条路上走多远。

我们生活在一张社会关系网中,因为别人能够看到你你才存在,这是《作为意识与表象的世界》,你看到的人、别人看到的你,都只是作为观察者的那个人想看到的,而非真实的人。虽然真实的人客观存在,但没有人能看到这样一个真实的、完整的人,包括你自己。

你看到你想看到的,他看到他想看到的,张三看到张三想看到的,李四看到李四想看到的……周围一圈人对你的意识构造了社会化关系中的你,但那只是你的一小部分。仅此而已。如果别人不知道你,你就不存在。为了存在,你就要在别人面前出现,这就是“存在感”。

所以现在很多人在刷微信、微博、博客、论坛、陌陌,都是在刷存在感。当然也包括我自己。

让别人知道你,你才存在。你只有留下点让别人难以忘怀的东西,你才因这些东西而存在。

如果想明白了这个道理,一个真正热爱技术的程序员,想在这个行当里干点儿事情的哥们姐们,就不会去在意别人说什么“软件开发是青春饭”、“程序员平均寿命低于普通人”、“程序员群体社会地位低下不如鸡”、“过了30就要另谋出路”之类的话。作为一个与其它行业没有什么差别的行业,仅仅是分工不同而已,为什么有这么多说法呢?众说纷纭,都是杂音。有用的话不这样,大音希声。其实黄小琥在《没那么简单》这首歌里也说了:

感觉快乐就忙东忙西

感觉累了就放空自己

别人说的话 随便听一听 自己作决定

不想拥有太多情绪

当然你也可以认为我通篇都是P话,真没关系。

程序员的两条主要通道

看图1很明白了,程序员有两条主要的职业通道:技术和管理。

在中国有个很不好的传统:学而优则仕。

如果你在一个单位干技术干了很多年,还当不上领导,就会被人瞧不起。这也是很多人干开发干了几年后,正当年富力强生产力旺盛的时候脱离技术通道的原因。因为领导大部分都是这么一个套路:“干得好?行,带人吧。带得好?行,升经理吧……”所以,很多原本可以成为技术大牛的人,就这么被拐走了。

也有一些专注搞技术的开发人员,就要走技术通道。

有个哥们儿,做 CMS ,前台后台都能搞,领导让他带三个人,让他当项目经理,他不乐意,说我自己干就行了,管别人净浪费时间。领导好说歹说把他绑在了项目经理的位置上,结果他不管那几个小伙伴,也不安排工作给人家,人家来问他这个怎么干,他就说你不用管了,我来干。最后呢,一个人干了80%以上的活儿,其它几个人闲得蛋疼。再后来呢,领导不住地找这哥们儿谈话,教育他怎么做项目经理……再后来这哥们儿就离职了……

“学而优则仕”还有一个非常不好的地方:普遍认为当领导的薪水要比高技术的高。这也是很多本来有灵气的开发人员想走管理路线的原因。我想干技术啊,可你们看不起我,不给我那么多钱,周围人也这么看,我没法老这么干下去。

其实如果你不在意这种周围的看法,做技术未尝不是一条幸福的路。

跳出三界外

前面我提到有同事搞金融去了,还有别的故事。

我原来有个同事,程序很厉害,是公司的高级工程师,后来不干了,开便利店去了。前几天有个朋友说他找了个合伙人包了点儿地在搞有机农业,种菜……

有个阿媛在淘宝上卖内衣,后来把工作辞了……

有个阿猿开了家咖啡馆,名字就叫程序员咖啡……

这都是跳出三界外的故事。其实也很平常,你的选择,你做主。如果你觉得这个行当不是人待的地方,再也不要受这罪了,那就走吧。如果一份工作带给你的痛苦比欢乐多很多,确实没有留恋的必要。真的,你肯定是走错了路。

我在看《高效程序员的45个习惯》时,第一章里引用了一句土耳其谚语,写在下面,送给诸位,也送给我自己。

不管路走了多远,错了就要重新返回。