美文网首页
Android中Gif网络图片下载到本地并通知相册显示

Android中Gif网络图片下载到本地并通知相册显示

作者: 光芒121 | 来源:发表于2021-06-01 21:48 被阅读0次

    把网络中的Gif和图片下载到本地,并通知系统相册显示,同时适配了Android Q版本,上代码(kotlin):

         thread {  //kotlin的异步代码块,并不是缩写,而是直接能运行
               var path = DownloadUtils.showLoadingImage(this, mUrl)  //必须异步调用处
               if (!path.isNullOrEmpty()) {
                  runOnUiThread {
                          ToastUtil.showLong("保存成功")
                   }
                }
         }
    
    showLoadingImage() 方法
           /**
             * 下载图片保存至手机并通知系统相册显示
             */
            fun showLoadingImage(context: Context, urlPath: String): String? {
                if (urlPath.isNullOrEmpty()) return null
                var mMimeType = urlPath.substring(urlPath.lastIndexOf("."), urlPath.length) // .gif还是.jpg
                var outImageUri: Uri? = null
                var outputStream: OutputStream? = null
                var inputStream: InputStream? = null
                var inBuffer: BufferedSource? = null
                try {
                    if (SdkVersionUtils.checkedAndroid_Q()) {   //针对Q版本创建uri
                        val contentValues = ContentValues()
                        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "IMG_" + SimpleDateFormat("yyyyMMdd_HHmmssSS").format(System.currentTimeMillis()) + mMimeType)
                        contentValues.put(MediaStore.Images.Media.DATE_TAKEN, ValueOf.toString(System.currentTimeMillis()))
                        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*")
                        contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM)
                        outImageUri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
                    } else {
                        val state = Environment.getExternalStorageState()
                        val rootDir = if (state == Environment.MEDIA_MOUNTED) Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) else context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
                        if (rootDir != null) {
                            if (!rootDir.exists()) {
                                rootDir.mkdirs()
                            }
                            val folderDir = File(if (state != Environment.MEDIA_MOUNTED) rootDir.absolutePath else rootDir.absolutePath + File.separator + PictureMimeType.CAMERA + File.separator)
                            if (!folderDir.exists() && folderDir.mkdirs()) {
                            }
                            val fileName ="IMG_" + SimpleDateFormat("yyyyMMdd_HHmmssSS").format(System.currentTimeMillis()) + mMimeType
                            val file = File(folderDir, fileName)
                            outImageUri = Uri.fromFile(file)
                        }
                    }
                    if (outImageUri != null) {
                        outputStream = Objects.requireNonNull(context.getContentResolver().openOutputStream(outImageUri))
                        val u = URL(urlPath)
                        inputStream = u.openStream()
                        inBuffer = inputStream.source().buffer()
                        val bufferCopy = MyFileUtils.bufferCopy(inBuffer, outputStream)
                        if (bufferCopy) {
                            var path = MyFileUtils.getPath(context, outImageUri)
                            /*--------------通知相册广播-----------------------------*/
                            // deprecated (4.4以后只有系统级应用才有使用广播通知系统扫描的权限)
                            val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
                            intent.data = outImageUri
                            context.sendBroadcast(intent)
                            MediaScannerConnection.scanFile(context, arrayOf(path), null) { path, uri -> Log.e("scan file ", "$path---$uri") }
                            /*--------------通知广播-----------------------------*/
                            return path
                        }
                    }
                } catch (e: Exception) {
                    if (outImageUri != null && SdkVersionUtils.checkedAndroid_Q()) {
                        context.getContentResolver().delete(outImageUri, null, null)
                    }
                } finally {
                    inputStream?.close()
                    outputStream?.close()
                    inBuffer?.close()
                }
                return null
            }
    
    MyFileUtils类中的方法直接全copy,里面也包含bufferCopy()方法
    import android.annotation.SuppressLint
    import android.content.ContentUris
    import android.content.Context
    import android.database.Cursor
    import android.net.Uri
    import android.os.Build
    import android.os.Environment
    import android.provider.DocumentsContract
    import android.provider.MediaStore
    import android.util.Log
    import okio.BufferedSink
    import okio.BufferedSource
    import okio.buffer
    import okio.sink
    import java.io.OutputStream
    import java.util.*
    
    class MyFileUtils{
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         * @author paulburke
         */
        fun isDownloadsDocument(uri: Uri): Boolean {
            return "com.android.providers.downloads.documents" == uri.authority
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is ExternalStorageProvider.
         * @author paulburke
         */
        fun isExternalStorageDocument(uri: Uri): Boolean {
            return "com.android.externalstorage.documents" == uri.authority
        }
    
        /**
         * Get a file path from a Uri. This will get the the path for Storage Access
         * Framework Documents, as well as the _data field for the MediaStore and
         * other file-based ContentProviders.<br></br>
         * <br></br>
         * Callers should check whether the path is local before assuming it
         * represents a local file.
         *
         * @param context The context.
         * @param uri     The Uri to query.
         * @author paulburke
         */
        @SuppressLint("NewApi")
        fun getPath(ctx: Context, uri: Uri): String? {
            val context = ctx.applicationContext
            val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
    
            // DocumentProvider
            if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
                if (isExternalStorageDocument(uri)) {
                    val docId = DocumentsContract.getDocumentId(uri)
                    val split = docId.split(":").toTypedArray()
                    val type = split[0]
                    if ("primary".equals(type, ignoreCase = true)) {
                        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            context.getExternalFilesDir(Environment.DIRECTORY_PICTURES).toString() + "/" + split[1]
                        } else {
                            Environment.getExternalStorageDirectory().toString() + "/" + split[1]
                        }
                    }
    
                } else if (isDownloadsDocument(uri)) {
                    val id = DocumentsContract.getDocumentId(uri)
                    val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
                    return getDataColumn(context, contentUri, null, null)
                } else if (isMediaDocument(uri)) {
                    val docId = DocumentsContract.getDocumentId(uri)
                    val split = docId.split(":").toTypedArray()
                    val type = split[0]
                    var contentUri: Uri? = null
                    if ("image" == type) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                    } else if ("video" == type) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                    } else if ("audio" == type) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                    }
                    val selection = "_id=?"
                    val selectionArgs = arrayOf(split[1])
                    return getDataColumn(context, contentUri, selection, selectionArgs)
                }
            } else if ("content".equals(uri.scheme, ignoreCase = true)) {
    
                // Return the remote address
                return if (isGooglePhotosUri(uri)) {
                    uri.lastPathSegment
                } else getDataColumn(context, uri, null, null)
            } else if ("file".equals(uri.scheme, ignoreCase = true)) {
                return uri.path
            }
            return null
        }
    
        /**
         * Get the value of the data column for this Uri. This is useful for
         * MediaStore Uris, and other file-based ContentProviders.
         *
         * @param context       The context.
         * @param uri           The Uri to query.
         * @param selection     (Optional) Filter used in the query.
         * @param selectionArgs (Optional) Selection arguments used in the query.
         * @return The value of the _data column, which is typically a file path.
         * @author paulburke
         */
        fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
            var cursor: Cursor? = null
            val column = "_data"
            val projection = arrayOf(column)
            try {
                cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
                if (cursor != null && cursor.moveToFirst()) {
                    val column_index = cursor.getColumnIndexOrThrow(column)
                    return cursor.getString(column_index)
                }
            } catch (ex: IllegalArgumentException) {
                Log.i("Query", String.format(Locale.getDefault(), "getDataColumn: _data - [%s]", ex.message))
            } finally {
                cursor?.close()
            }
            return null
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         * @author paulburke
         */
        fun isMediaDocument(uri: Uri): Boolean {
            return "com.android.providers.media.documents" == uri.authority
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is Google Photos.
         */
        fun isGooglePhotosUri(uri: Uri): Boolean {
            return "com.google.android.apps.photos.content" == uri.authority
        }
    
        fun bufferCopy(inBuffer: BufferedSource?, outputStream: OutputStream?): Boolean {
            var outBuffer: BufferedSink? = null
            try {
                outBuffer = outputStream?.sink()?.buffer()
                inBuffer?.let {
                    outBuffer?.writeAll(it)
                }
                outBuffer?.flush()
                return true
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                inBuffer?.close()
                outBuffer?.close()
            }
            return false
        }
    }
    

    相关文章

      网友评论

          本文标题:Android中Gif网络图片下载到本地并通知相册显示

          本文链接:https://www.haomeiwen.com/subject/shugsltx.html