用kotlin方式打開《第一行代碼:Android》之開發酷歐天氣(最終版)

參考:《第一行代碼:Android》第2版——郭霖html

注1:本文爲原創,例子可參考郭前輩著做:《第一行代碼:Android》第2版java

注2:本文不贅述android開發的基本理論,不介紹入門知識,不介紹Android Studio基本安裝,開門見山,直接使用kotlin改寫郭前輩的《第一行代碼:Android》中的部分例子,有機會的話本身作一些新例子出來!android

注3:本文嘗試用Google新官推語言kotlin改寫《第一行代碼:Android》中的案例,偶爾涉及java做爲對比git

注4:開發基於Android Studio 3.0,而且新建項目時勾選「support kotlin」github

進入實戰——開發酷歐天氣(3)

14.6 手動更新天氣和切換城市(原書p532)web

不知不覺已經接觸kotlin的第四天了,原書中的最後一個實踐項目「酷歐天氣」也改寫的差很少了,稍後會將源碼上傳至csdn!做爲代碼樣本吧!canvas

每日一圖作背景

雖說如今咱們已經把天氣界面編寫的很是不錯了,不過和市場上的一些天氣軟件的界面比起來,仍然還有必定差距的。(原書p526)api

配置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

相關文章
相關標籤/搜索