亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Kotlin實(shí)現(xiàn)網(wǎng)絡(luò)圖片下載和保存功能

 更新時(shí)間:2023年02月07日 09:51:55   作者:振華OPPO  
根據(jù)Android多線程和網(wǎng)絡(luò)編程的知識(shí)講解和案例使用,使用Handler消息機(jī)制實(shí)現(xiàn)網(wǎng)絡(luò)圖片下載,并且保存到模擬器中,強(qiáng)化對(duì)Android多線程編程、網(wǎng)絡(luò)編程和文件讀寫的理解,這篇文章主要介紹了Kotlin實(shí)現(xiàn)網(wǎng)絡(luò)圖片下載和保存功能,需要的朋友可以參考下

一、理論基礎(chǔ)

  • 掌握Kotlin面向?qū)ο蟮能浖_發(fā)方面的基礎(chǔ)知識(shí)。
  • 鞏固前期Activity、UI控件的使用。
  • 掌握Handler和Http請(qǐng)求的特點(diǎn)及用法。

二、實(shí)驗(yàn)?zāi)康?/h2>

根據(jù)Android多線程和網(wǎng)絡(luò)編程的知識(shí)講解和案例使用,使用Handler消息機(jī)制實(shí)現(xiàn)網(wǎng)絡(luò)圖片下載,并且保存到模擬器中,強(qiáng)化對(duì)Android多線程編程、網(wǎng)絡(luò)編程和文件讀寫的理解。要求:

  • 鞏固Android應(yīng)用開發(fā)工具(Android Studio)的常規(guī)用法;
  • 鞏固Activity、UI控件的常規(guī)用法;
  • 掌握Handler的編程要點(diǎn);
  • 掌握HTTP獲取網(wǎng)絡(luò)資源的方法。
  • 掌握文件輸入輸出流的寫法。

三、實(shí)驗(yàn)步驟

1、新建工程文件

首先打開Android Studio,新建Project,命名為WebDownload,Language為Kotlin,Minimum SDK選擇API 22,然后包名就是com.android.webdownload,回車創(chuàng)建成功,等待下載依賴進(jìn)行build。

2、引入布局管理

首先在模塊的build.gradle中加上下面的閉包,然后同步

 buildFeatures {
     viewBinding true
 }

在MainActivity里面先定義變量,

private lateinit var binding: ActivityMainBinding

在onCreate()方法中,添加如下代碼:

 binding = ActivityMainBinding.inflate(layoutInflater)
 setContentView(binding.root)

這下,我們想訪問某個(gè)控件,直接通過binding對(duì)象獲取即可,比如:

binding.tvShow.text = "下載成功!"

3、創(chuàng)建布局

外層父容器選擇LinearLayout,內(nèi)部元素對(duì)齊方式選擇vertical,從上至下放了一個(gè)ProgressBar,設(shè)置了max為100,進(jìn)度條顯示下載進(jìn)度。接著是一個(gè)TextView,顯示下載信息;ImageView是圖片框,顯示圖片。還有下載圖片和終止下載兩個(gè)按鈕在最底下。里面的textSize和textColor這些屬性就自定義設(shè)置,沒什么可講的。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <ProgressBar
        android:id="@+id/progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:layout_marginBottom="20dp"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"/>
    <TextView
        android:id="@+id/tv_show"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:layout_margin="10dp"
        android:gravity="center" />
    <ImageView
        android:id="@+id/iv_show"
        android:layout_width="400dp"
        android:layout_height="400dp"
        android:layout_gravity="center"
        android:background="@mipmap/ic_launcher"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btn_download"
            android:layout_width="0dp"
            android:text="下載圖片"
            android:layout_margin="10dp"
            android:textSize="20sp"
            android:padding="10dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:id="@+id/btn_stop"
            android:layout_width="0dp"
            android:text="終止下載"
            android:layout_margin="10dp"
            android:textSize="20sp"
            android:padding="10dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
    </LinearLayout>
</LinearLayout>

來看下簡(jiǎn)單的布局,實(shí)現(xiàn)效果就是點(diǎn)擊下載,開始下載網(wǎng)絡(luò)圖片,下載好后顯示在圖片框上,而且保存到模擬器的存儲(chǔ)空間中,下載過程中可以停止下載(如果你的手速比網(wǎng)速快的前提):

4、訪問權(quán)限

因?yàn)橐l(fā)送網(wǎng)絡(luò)請(qǐng)求,所以需要訪問網(wǎng)絡(luò),因?yàn)橐3謭D片到模擬器,所以要文件讀取,還要有向SD卡中創(chuàng)建或者刪除的權(quán)限。網(wǎng)絡(luò)是不需要?jiǎng)討B(tài)申請(qǐng)的,但后面兩個(gè)權(quán)限需要。

    <!-- 訪問網(wǎng)絡(luò)的權(quán)限 -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- 文件讀取的權(quán)限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!-- 向SD卡中創(chuàng)建或者刪除的權(quán)限。 -->
    <uses-permission android:name="andorid.permission.MONUN_UNMOUNT_FILESYSTEMS"/>

動(dòng)態(tài)申請(qǐng)權(quán)限的代碼:

   if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
       ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
   }

在彈出對(duì)話框用戶操作之后,返回應(yīng)用權(quán)限請(qǐng)求的結(jié)果。requestCode是請(qǐng)求碼,permissions是權(quán)限列表,grantResults是允許的結(jié)果數(shù)組。運(yùn)用if-else分支完成同意權(quán)限和不同意的邏輯。

override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when(requestCode) {
            1-> {
                if (grantResults.isNotEmpty() &&
                        grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "你可以正常使用app", Toast.LENGTH_SHORT).show()
                } else {
                    Toast.makeText(this, "你拒絕了權(quán)限,無(wú)法正常保存圖片", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

5、實(shí)現(xiàn)邏輯

首先也是最核心的就是從網(wǎng)絡(luò)上下載圖片,顯然可以用HttpURLConnection或者OkHttp或者其他更好的網(wǎng)絡(luò)框架,總之就是和url地址創(chuàng)建輸入流,讀取文件,保存為bitmap格式返回,然后關(guān)閉輸入流。

    // 下載圖片,轉(zhuǎn)為位圖
    fun getImage(imageUrl: String): Bitmap? {
        var myBitmap:Bitmap? = null
        var connection:HttpURLConnection
        try {
            var url = URL(imageUrl)
            connection = url.openConnection() as HttpURLConnection
            connection.connectTimeout = 8000
            connection.doInput = true
            connection.useCaches = false
            val myInput = connection.inputStream
            myBitmap = BitmapFactory.decodeStream(myInput)
            myInput.close()
        } catch (e:Exception) {
            e.printStackTrace()
        }
        return myBitmap;
    }

接下來是保存圖片到模擬器外部存儲(chǔ),這一點(diǎn)就是文件的IO流,Java中流的知識(shí)太常用了。先定義目錄,如果不存在則創(chuàng)建目錄。try-catch包圍圈里面創(chuàng)建輸出流,保存的地址就是在之前的文件夾路徑基礎(chǔ)上加上了文件名和后綴,然后bitmap按照指定圖像格式進(jìn)行壓縮,最后關(guān)閉輸出流。

// 保存位圖到本地路徑
    private fun saveImage(bitmap:Bitmap?) {
        var file = File(saveDirs)
        // 如果文件不存在則創(chuàng)建目錄
        if (!file.exists()) {
            if (file.mkdir()) {
                Log.d("test", "mkdir")
            } else {
                Log.d("test", "failed")
            }
        }
        try {
            val fileOutputStream = FileOutputStream(savePath)
            bitmap?.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)
            fileOutputStream.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

這里的saveImage和savePath要著重講下,不然很容易運(yùn)行后圖片無(wú)法保存到本地,原來都是路徑?jīng)]有搞清楚的問題。var file = File(saveDirs)是創(chuàng)建文件夾。savePath才是圖片的保存路徑,如果savePath寫的是"\android\scared\0\storage之類的"那是怎么也訪問不了存儲(chǔ)空間的。

private val saveDirs:String = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString()
private val savePath:String = saveDirs + File.separator + System.currentTimeMillis() + ".png"

最后就是在子線程中下載網(wǎng)絡(luò)圖片并使用Handler發(fā)送message消息了,這段邏輯反而是最簡(jiǎn)單的部分??梢钥吹綔?zhǔn)備下載前和下載完成后都發(fā)送message。what分別是0和1。

    // 創(chuàng)建下載圖片的子線程,準(zhǔn)備下載前和下載完成后都發(fā)送message
    val thread1 = Thread {
        val message = Message()
        message.what = 0
        handler.sendMessage(message)
        bitmap = getImage(url)
        val message2 = Message()
        message2.what = 1
        handler.sendMessage(message2)
    }

定義全局變量handler來接收自己發(fā)給自己的消息,0那就模擬進(jìn)度條下載進(jìn)度(因?yàn)榫W(wǎng)絡(luò)圖片的進(jìn)度無(wú)法通過子線程預(yù)先獲取到,這是后驗(yàn)的)。1就是binding.ivShow.setImageBitmap(bitmap)設(shè)置位圖,文本為"下載成功!",提示消息也為"下載已完成"

    val handler:Handler = Handler {
        when(it.what) {
            0-> {
                for (i in 0..100) binding.progress.progress = i
            }
            1 -> {
                binding.ivShow.background = null
                binding.ivShow.setImageBitmap(bitmap)
                saveImage(bitmap)
                binding.tvShow.text = "下載成功!"
                Toast.makeText(this, "下載已完成", Toast.LENGTH_SHORT).show()
            }
            else -> Log.d("Test", "else")
        }
        false
    };

開始下載按鈕就是開啟線程,停止下載按鈕就是終止線程。

		binding.btnDownload.setOnClickListener({
            try {
                thread1.start()
            } catch (e:Exception) {
                e.printStackTrace()
            }
        })
        binding.btnStop.setOnClickListener({
            if (thread1.isAlive) {
                thread1.interrupt()
                Toast.makeText(this, "interrupt()", Toast.LENGTH_SHORT).show()
            }
            if (!thread1.isAlive) {
                binding.tvShow.text = "下載終止!"
                Toast.makeText(this, "下載已終止", Toast.LENGTH_SHORT).show()
            }
        })

完整的MainActivity代碼如下:

package com.android.webdownload

import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.*
import androidx.appcompat.app.AppCompatActivity
import android.util.Log
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.android.webdownload.databinding.ActivityMainBinding

import java.io.File
import java.io.FileOutputStream
import java.lang.Exception
import java.lang.ref.WeakReference
import java.net.HttpURLConnection
import java.net.URL
import java.util.jar.Manifest

class MainActivity : AppCompatActivity() {
    private var bitmap:Bitmap? = null
    private lateinit var binding: ActivityMainBinding
    private val url:String = "http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg"
    private val saveDirs:String = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString()
    private val savePath:String = saveDirs + File.separator + System.currentTimeMillis() + ".png"
    val handler:Handler = Handler {
        when(it.what) {
            0-> {
                for (i in 0..100) binding.progress.progress = i
            }
            1 -> {
                binding.ivShow.background = null
                binding.ivShow.setImageBitmap(bitmap)
                saveImage(bitmap)
                binding.tvShow.text = "下載成功!"
                Toast.makeText(this, "下載已完成", Toast.LENGTH_SHORT).show()
            }
            else -> Log.d("Test", "else")
        }
        false
    };
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
        }
        binding.btnDownload.setOnClickListener({
            try {
                thread1.start()
            } catch (e:Exception) {
                e.printStackTrace()
            }
        })
        binding.btnStop.setOnClickListener({
            if (thread1.isAlive) {
                thread1.interrupt()
                Toast.makeText(this, "interrupt()", Toast.LENGTH_SHORT).show()
            }
            if (!thread1.isAlive) {
                binding.tvShow.text = "下載終止!"
                Toast.makeText(this, "下載已終止", Toast.LENGTH_SHORT).show()
            }
        })
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when(requestCode) {
            1-> {
                if (grantResults.isNotEmpty() &&
                        grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "你可以正常使用app", Toast.LENGTH_SHORT).show()
                } else {
                    Toast.makeText(this, "你拒絕了權(quán)限,無(wú)法正常保存圖片", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    // 創(chuàng)建下載圖片的子線程,準(zhǔn)備下載前和下載完成后都發(fā)送message
    val thread1 = Thread {
        val message = Message()
        message.what = 0
        handler.sendMessage(message)
        bitmap = getImage(url)
        val message2 = Message()
        message2.what = 1
        handler.sendMessage(message2)
    }

    // 下載圖片,轉(zhuǎn)為位圖
    fun getImage(imageUrl: String): Bitmap? {
        var myBitmap:Bitmap? = null
        var connection:HttpURLConnection
        try {
            var url = URL(imageUrl)
            connection = url.openConnection() as HttpURLConnection
            connection.connectTimeout = 8000
            connection.doInput = true
            connection.useCaches = false
            val myInput = connection.inputStream
            myBitmap = BitmapFactory.decodeStream(myInput)
            myInput.close()
        } catch (e:Exception) {
            e.printStackTrace()
        }
        return myBitmap;
    }

    // 保存位圖到本地路徑
    private fun saveImage(bitmap:Bitmap?) {
        var file = File(saveDirs)
        // 如果文件不存在則創(chuàng)建目錄
        if (!file.exists()) {
            if (file.mkdir()) {
                Log.d("test", "mkdir")
            } else {
                Log.d("test", "failed")
            }
        }
        try {
            val fileOutputStream = FileOutputStream(savePath)
            bitmap?.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)
            fileOutputStream.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

四、實(shí)驗(yàn)演示

1、首先看到啟動(dòng)頁(yè)面就是下載頁(yè)面,頂部的進(jìn)度條和TextView并沒有顯示出來,因?yàn)闆]有內(nèi)容。

2、點(diǎn)擊下載圖片按鈕,圖片很快下載完成,并且頂部進(jìn)度條也加載完畢了,圖片下載好后顯示在屏幕中央。在下載過程中可以停止下載,不過由于下載過快,根本來不及停止。

3、打開文件,選擇Android SDK built for x86

選擇Pictures

可以看到剛剛下載好的圖片

點(diǎn)擊全圖查看

五、實(shí)驗(yàn)總結(jié)

總體上來說還是非?;A(chǔ)的內(nèi)容,考察的點(diǎn)不多,可以作為學(xué)習(xí)Kotlin的點(diǎn)心食用,中間需要注意的小地方還是有的。越是簡(jiǎn)單的東西遇到的問題越多,多練習(xí)才是王道。

腳本之家本地下載

源代碼已上傳GitHub,點(diǎn)擊下載源代碼

到此這篇關(guān)于Kotlin實(shí)現(xiàn)網(wǎng)絡(luò)圖片下載和保存功能的文章就介紹到這了,更多相關(guān)Kotlin網(wǎng)絡(luò)圖片下載和保存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論