BaseMVVMActivity

BaseMVVMActivity

import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.NetworkRequest
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.WindowManager
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.epuxun.drink.utli.http.NetworkCallbackImpl
import java.io.File
import java.util.*

abstract class BaseMVVMActivity<T : ViewModel> : AppCompatActivity() {

    //下載的apk的文件名
    private val apkName = "drink.apk"
    private var apkId = -1L
    private var downloadManager:DownloadManager? = null

    private val loadDialog by lazy {
        val dialog = LoadDialog
        dialog.isCancelable = false
        dialog
    }

    private var onMeasureSizeCallback: OnMeasureSizeCallback? = null
    private lateinit var views: Array<out View>

    private var connectivityManager: ConnectivityManager? = null
    private val networkCallback by lazy {
        NetworkCallbackImpl
    }

    private var receiver: BroadcastReceiver? = null
    private var externalReceiver: BroadcastReceiver? = null

    //獲取ViewModel,implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc02'
    val viewModel by lazy {
        ViewModelProvider(this).get(getViewModel())
    }

    abstract fun getLayoutResID(): Int

    abstract fun addObserver(): LifecycleObserver?

    abstract fun getViewModel(): Class<T>

    abstract fun onCreate()

    override fun onCreate(savedInstanceState: Bundle?) {
        //防止截屏攻擊風險
        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
        //仿系統自帶短信界面 可以完全漂浮在軟鍵盤之上
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE or WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
        super.onCreate(savedInstanceState)

        setContentView(getLayoutResID())
        //綁定組件的聲明週期
        addObserver()?.let {
            lifecycle.addObserver(it)
        }

        onCreate()
    }

    /**
     * 顯示加載Dialog
     */
    fun showLoadDialog() {
        loadDialog.show(supportFragmentManager, localClassName)
    }

    /**
     * 關閉加載Dialog
     */
    fun dismissLoadDialog() {
        loadDialog.dismiss()
    }

    /**
     * EditText的值動態賦予MutableLiveData
     */
    fun setEditTextMutableLiveData(et: EditText, liveData: MutableLiveData<String>) {
        et.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                liveData.value = s.toString()
            }
        })
    }

    /**
     * 獲取控件大小接口
     */
    interface OnMeasureSizeCallback {
        fun getMeasureSize(view: View)
    }

    /**
     * 設置獲取控件大小的回調
     */
    fun setOnMeasureSizeCallback(onMeasureSizeCallback: OnMeasureSizeCallback, vararg views: View) {
        this.onMeasureSizeCallback = onMeasureSizeCallback
        this.views = views
    }

    /**
     * 獲取焦點時調用獲取控件大小的回調
     */
    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (hasFocus) {
            onMeasureSizeCallback?.let { onMeasureSizeCallback ->
                for (view in views) {
                    onMeasureSizeCallback.getMeasureSize(view)
                }
            }
        }
        //沉浸狀態欄
//        if (hasFocus && Build.VERSION.SDK_INT >= 21) {
//            val decorView = window.decorView
//            decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
//                    or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
//                    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
//                    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
//                    or View.SYSTEM_UI_FLAG_FULLSCREEN
//                    or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
//            window.navigationBarColor = Color.TRANSPARENT//設置虛擬按鍵透明
//            window.statusBarColor = Color.TRANSPARENT//設置狀態欄透明
//        } else if (hasFocus && Build.VERSION.SDK_INT >= 19) {
//            val decorView = window.decorView
//            decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
//                    or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
//                    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
//                    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
//                    or View.SYSTEM_UI_FLAG_FULLSCREEN
//                    or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
//        }
    }

    /**
     * 註冊全局廣播,關閉Activity時會自動註銷本地廣播
     */
    fun registerExternalReceiver(receiver: BroadcastReceiver, vararg actions: String) {
        this.externalReceiver = receiver
        val filter = IntentFilter()
        for (action in actions) {
            filter.addAction(action)
        }
        registerReceiver(receiver, filter)
    }

    /**
     * 自動註銷全局廣播
     */
    private fun unregisterExternalReceiver() {
        externalReceiver?.let {
            unregisterReceiver(it)
        }
    }

    /**
     * 安裝apk Dialog
     */
    fun showInstallationDialog(url: String,requestCode: Int) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (packageManager.canRequestPackageInstalls()) {
                showDialogN(url)
            } else {
                val builder = AlertDialog.Builder(this)
                builder.setTitle("檢測到新版本")
                    .setMessage("安裝新版本需要打開未知來源權限,請去設置中開啓權限")
                    .setPositiveButton("設置") { _, _ ->
                        val selfPackageUri = Uri.parse("package:$packageName")
                        val intentPermission =
                            Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, selfPackageUri)
                        //8.0以上跳轉至“安裝未知應用”權限界面,引導用戶開啓權限
                        startActivityForResult(intentPermission, requestCode)
                    }
                    .setNegativeButton("取消") { _, _ -> }
                    .setCancelable(false)
                    .show()
            }
        } else {
            showDialogN(url)
        }
    }

    /**
     * 7.0以下新版本提示
     */
    private fun showDialogN(url:String) {
        val builder = AlertDialog.Builder(this)
        builder.setTitle("提示")
            .setMessage("檢測到新版本是否更新")
            .setPositiveButton("更新") { _, _ -> apkUpdate(url) }
            .setNegativeButton("取消") { _, _ -> }
            .setCancelable(false)
            .show()
    }

    /**
     * 下載apk
     */
    private fun apkUpdate(url: String) {
        val request = DownloadManager.Request(Uri.parse(url))

        //設置什麼網絡情況下可以下載
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE or DownloadManager.Request.NETWORK_WIFI)

        //設置通知欄的標題
        request.setTitle("版本更新")
        //設置通知欄的message
        request.setDescription("正在進行版本更新.....")
        //是否在通知欄顯示下載進度,默認顯示
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)

        //設置文件存放目錄
        request.setDestinationInExternalFilesDir(
            application,
            Environment.DIRECTORY_DOWNLOADS,
            apkName
        )
        //獲取系統服務
        downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        //進行下載
        downloadManager?.let {
            apkId = it.enqueue(request)
        }
    }

    /**
     * 取消下載apk
     */
    fun removeApk(){
        downloadManager?.remove(apkId)
    }

    /**
     * 安裝apk
     */
    fun installation() {
        val path = Objects.requireNonNull<File>(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS))
            .absolutePath
        val file = File(path, apkName)

        val intent = Intent(Intent.ACTION_VIEW)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

        //判讀版本是否在7.0以上
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val authority = "$packageName.fileProvider"
            //生成File URI
            val apkUri = FileProvider.getUriForFile(this, authority, file)
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
        } else {
            //Uri.fromFile(file) 生成File URI
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive")
        }

        startActivity(intent)
    }

    /**
     * 註冊網絡監聽
     */
    fun registerNetworkMonitoring() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManager =
                getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            //需要<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />權限
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                connectivityManager?.registerDefaultNetworkCallback(networkCallback)
            } else {
                connectivityManager?.registerNetworkCallback(
                    NetworkRequest.Builder().build(),
                    networkCallback
                )
            }
        }
    }

    /**
     * 註銷網絡監聽
     */
    private fun unregisterNetworkMonitoring() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManager?.unregisterNetworkCallback(networkCallback)
        }
    }

    /**
     * 重寫startActivity
     *
     * @param clz 跳轉頁面的class
     */
    fun startActivity(clz: Class<*>) {
        val intent = Intent(this, clz)
        startActivity(intent)
        enterTransitionAnim()
    }

    /**
     * 重寫startActivity
     *
     * @param clz    跳轉頁面的class
     * @param bundle 攜帶的數據
     */
    fun startActivity(clz: Class<*>, bundle: Bundle) {
        val intent = Intent(this, clz)
        intent.putExtras(bundle)
        startActivity(intent)
        enterTransitionAnim()
    }

    fun startActivityForResult(clz: Class<*>, requestCode: Int) {
        val intent = Intent(this, clz)
        startActivityForResult(intent, requestCode)
        enterTransitionAnim()
    }

    fun startActivityForResult(clz: Class<*>, requestCode: Int, bundle: Bundle) {
        val intent = Intent(this, clz)
        startActivityForResult(intent, requestCode, bundle)
        enterTransitionAnim()
    }

    fun getIntentBundle(): Bundle? {
        return intent.extras
    }

    /**
     * 進入Activity過渡動畫
     */
    private fun enterTransitionAnim() {
        overridePendingTransition(android.R.anim.fade_out, android.R.anim.fade_in)
    }

    /**
     * 退出Activity過渡動畫
     */
    private fun quitTransitionAnim() {
        overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
    }

    override fun onBackPressed() {
        super.onBackPressed()
        // Fragment 逐個出棧
        val count = supportFragmentManager.backStackEntryCount
        if (count == 0) {
            super.onBackPressed()
        } else {
            supportFragmentManager.popBackStack()
        }
    }

    override fun finish() {
        super.finish()
        quitTransitionAnim()
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterExternalReceiver()
        unregisterNetworkMonitoring()
    }
}

進度條dialog

object LoadDialog : DialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        //設置透明背景
        dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        return inflater.inflate(R.layout.dialog_progress_bar, container, false)
    }
}

網絡狀態

import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import androidx.annotation.RequiresApi
import com.epuxun.drink.utli.setNetworkConnected

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
object NetworkCallbackImpl : ConnectivityManager.NetworkCallback() {

    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        //網絡已連接
        setNetworkConnected(true)
    }

    override fun onLost(network: Network) {
        super.onLost(network)
        //網絡已斷開
        setNetworkConnected(false)
    }

    override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
        super.onCapabilitiesChanged(network, networkCapabilities)
        if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
            if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {//網絡類型爲wifi

            } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {//蜂窩網絡

            } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {//藍牙

            } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {//以太網

            } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {//Wi-Fi Aware

            } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {//LoWPAN

            } else { //其他網絡

            }
        }
    }

}

在Utlis類中

//網絡是否連接
private var isNetworkConnected: Boolean? = null
/**
 * 設置網絡狀態
 */
fun setNetworkConnected(boolean: Boolean){
    isNetworkConnected = boolean
}

/**
 * 檢測網絡是否連接
 * 如果未註冊[registerNetworkMonitoring] 會使用isNetworkConnectedLOLLIPOP
 */
fun isNetworkConnected(): Boolean {
    isNetworkConnected?.let {
        return it
    }
    return isNetworkConnectedLOLLIPOP()
}

/**
 * 5.0以下檢測網絡是否連接
 */
private fun isNetworkConnectedLOLLIPOP(): Boolean {
    val mConnectivityManager =
        application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    mConnectivityManager.getActiveNetworkInfo()?.let {
        return it.isAvailable()
    }
    return false
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章