用kotlin方式打开《第一行代码:Android》之开发酷欧天气(最终版)

参考:《第一行代码:Android》第2版——郭霖

注1:本文为原创,例子可参考郭前辈著作:《第一行代码:Android》第2版

注2:本文不赘述android开发的基本理论,不介绍入门知识,不介绍Android Studio基本安装,开门见山,直接使用kotlin改写郭前辈的《第一行代码:Android》中的部分例子,有机会的话自己做一些新例子出来!

注3:本文尝试用Google新官推语言kotlin改写《第一行代码:Android》中的案例,偶尔涉及java作为对比

注4:开发基于Android Studio 3.0,并且新建项目时勾选“support kotlin”

进入实战——开发酷欧天气(3)

14.6 手动更新天气和切换城市(原书p532)

不知不觉已经接触kotlin的第四天了,原书中的最后一个实践项目“酷欧天气”也改写的差不多了,稍后会将源码上传至csdn!作为代码样本吧!

每日一图做背景

虽然说现在我们已经把天气界面编写的非常不错了,不过和市场上的一些天气软件的界面比起来,仍然还有一定差距的。(原书p526)

配置build.gradle

为了加载bing.com的每日一图到本地缓存,我们需要添加一个外部类库glide

关于glide:http://blog.csdn.net/fancylovejava/article/details/44747759

build.gradle:

dependencies {
......
    compile "com.github.bumptech.glide:glide:3.8.0"

}

添加glide到gradle,sync一下

最终布局activity_weather.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">

    <ImageView
        android:id="@+id/bing_pic_img"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />

    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ScrollView
                android:id="@+id/weather_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:overScrollMode="never"
                android:scrollbars="none">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:fitsSystemWindows="true"
                    android:orientation="vertical">

                    <include layout="@layout/title" />

                    <include layout="@layout/now" />

                    <include layout="@layout/forecast" />

                    <include layout="@layout/aqi" />

                    <include layout="@layout/suggestion" />
                </LinearLayout>
            </ScrollView>
        </android.support.v4.widget.SwipeRefreshLayout>

        <fragment
            android:id="@+id/choose_area_fragment"
            android:name="cn.cslg.weatherkotlin.ChooseAreaFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            />

    </android.support.v4.widget.DrawerLayout>

</FrameLayout>

注意:可以看到新增了一个ImageView,他就是我们用来放背景的容器,由于他的外部是一个FrameLayout,所以他和他的兄弟节点的内容会靠左上角停放,那么这个ImageView将和其他的内容重叠,造出一种背景的效果

修改WeatherActivity.kt:

......

class WeatherActivity : AppCompatActivity() {
......
    private var bingImg: ImageView? = null
......
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //状态栏透明化
        if (Build.VERSION.SDK_INT >= 21) {
            val v = window.decorView
            v.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            window.statusBarColor = Color.TRANSPARENT
        }
        bingImg = find<ImageView>(R.id.bing_pic_img)
       ......
    }

 ......

    //获取每日一图的API
    private fun loadBingImg() {
        val url = "http://guolin.tech/api/bing_pic"
        async {
            val s = URL(url).readText()
            uiThread {
                Glide.with(this@WeatherActivity).load(s).into(bingImg)
            }
        }
    }
}

注意:我们添加了loadBingImg方法,专门加载每日一图,其中多线程结束后,使用了Glide将图片在进入ImageView当中变成背景。

我们还把状态栏设置为透明,并且将他变成应用的一部分(应用全屏了),此时状态栏可能会和下面的内容挨得太近了,需要在xml中设置:fitsSystemWindows=”true”,空出一段空间来

手动更新天气

实现下拉刷新当前选定城市的天气信息

布局文件activity_weather.xml上面已经给出最终版本

主要添加了一个SwipeRefreshLayout容器,这个容器可以使用下拉刷新功能,将需要刷新的页面全部包含进去

修改WeatherActivity.kt:

......

class WeatherActivity : AppCompatActivity() {

......
    var swipeRefresh: SwipeRefreshLayout? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_weather)

        swipeRefresh = find<SwipeRefreshLayout>(R.id.swipe_refresh)
        swipeRefresh!!.setColorSchemeResources(R.color.colorPrimary)
        ......

        val weatherId = defaultSharedPreferences.getString("weather_id","")
        weatherLayout!!.visibility = View.INVISIBLE
        requestWeather(weatherId)
        swipeRefresh!!.setOnRefreshListener {
            //刷新当前的城市weather_id
            requestWeather(defaultSharedPreferences.getString("weather_id",""))
        }
    }

    //从服务器加载天气信息
    fun requestWeather(wid: String) {
        val url = "http://guolin.tech/api/weather?cityid=" + wid + "&key=" + KEY
        async {
            val s = URL(url).readText()

            uiThread {
                val weather = Gson().fromJson(s, Weather::class.java)
                //关闭下拉刷新
                swipeRefresh!!.isRefreshing = false
                Log.d("url",url)
                Log.d("url",weather.toString())
                showWeatherInfo(weather.HeWeather[0])
            }
        }
    }

    ......
}

注意:获取到了SwipeRefreshLayout控件,使用setColorSchemeResources设置了颜色,setOnRefreshListener设置了下拉刷新事件的监听。

切换城市

将ChooseAreaFragment这个碎片放到了offcanvas(侧滑)当中,实现侧滑后选择其他城市

在title.xml添加一个显示offcanvas的按钮:

<?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="?attr/actionBarSize"
    >

    <Button
        android:id="@+id/nav_button"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_alignParentLeft="true"
        android:layout_centerInParent="true"
        android:layout_marginLeft="10dp"
        android:background="@android:drawable/ic_menu_sort_by_size" />

......

</RelativeLayout>

修改activity_weather.xml(详见前面的最终布局)

主要添加了一个DrawerLayout,用于存放两个直子控件,第一个是主屏幕显示内容,第二个是侧滑内容

修改WeatherActivity.kt:

......

class WeatherActivity : AppCompatActivity() {

......
    private var navButton:Button?=null
    var drawLayout:DrawerLayout?=null
  ......
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
.....

        drawLayout = find<DrawerLayout>(R.id.drawer_layout)
        navButton = find<Button>(R.id.nav_button)
        navButton!!.setOnClickListener{
            drawLayout!!.openDrawer(GravityCompat.START)
        }

    }

   ......
}

注意:仅仅是添加了按钮触发事件和获取DrawerLayout的控件

修改:ChooseAreaFragment.kt

......

class ChooseAreaFragment : Fragment() {
    ......
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        //列表点击监听事件
        listView!!.setOnItemClickListener {
            _, _, position, _ ->
            when (current_level) {
......
                LEVEL_COUNTY -> {
                    selectedCounty = countyList[position]
                    defaultSharedPreferences.edit().putString("weather_id", selectedCounty!!.weather_id).apply()
                    if (activity is MainActivity) {
                        startActivity<WeatherActivity>()
                        activity.finish()   //将MainActivity销毁掉
                    } else if (activity is WeatherActivity) {
                        val act = activity as WeatherActivity
                        act.drawLayout!!.closeDrawers()
                        act.swipeRefresh!!.isRefreshing = true      //显示下拉刷新
                        act.requestWeather(selectedCounty!!.weather_id)
                    }
                }
            }
        }
......
    }

   ......
}

注意:在Fragment获取activity中的控件,kotlin的anko库可以直接使用activity,然后调用其它activity里的属性,比如swipeRefresh和drawLayout属性,当然前提是他们是public,不可以像其他仅仅在当前类下用的控件那样设置为private!

当用户触发选择了城市的事件后,将会去请求服务器的天气信息,在这之前应该将选择的城市的weather_id保存到SharedPreferences中,这样用户不必每次打开app时都要选择城市,app可以自己根据上次的选择请求天气数据

kotlin中使用is来代替java中的instanceof,可以用来判断当前实例所属类

如果是MainActivity,则进入WeatherActivity中(其实这表示app是用户第一次打开,还没有选择过城市)

anko库提供了startActivity<>方法,直接启动其他的活动
anko库的一些辅助方法:http://www.tuicool.com/articles/VrIjIjq

如果是WeatherActivity则关闭侧滑和下拉刷新,立即请求数据去!

效果

这里写图片描述

这里写图片描述

这里写图片描述

结语

至此,就把原书中的“酷欧天气”的例子使用kotlin语言重写了

代码下载:http://download.csdn.net/detail/u014466109/9851378

虽然我在这之前从来没有接触过kotlin语言,甚至闻所未闻(希望不要说我孤陋寡闻,毕竟我在这之前连Android都没写过,我的专长算是web)

但此时我想我爱上了kotlin这门现代语言

总结一下相对java开发的一些优点:

  1. 100%兼容java所有类库
  2. 每一行kotlin可以节约3-4行的java代码
  3. anko库简直就是Android界的jQuery,简化和封装了许多原本很长参数很多的方法
  4. data class类让你少些多少文件,你没必要理会那些一个类一个文件的java pojo,也不需要自己写get set方法
  5. 严格且安全的null类型
  6. val,var变量自动推断变量类型
  7. val变量适合多线程,并发安全
  8. 没有无聊的分号!
  9. 性能,有过之而无不及
  10. 清晰的lambda表达式,可代替难看复杂的匿名类

版权

转载请注明:http://www.cnblogs.com/devilyouwei/p/6901264.html

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

devilyouwei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值