Android
Activity跳转Fragment
1 | binding.fab.setOnClickListener { view -> |
使用XXPermissions
请求权限
首先添加远程仓库:
1 | dependencyResolutionManagement { |
然后引入依赖:
1 | android { |
使用:
1 | XXPermissions.with(this) |
安卓启用储存
1 | 直接在main activity中: |
Permissions.kt
1 | package cn.rmshadows.weatherpost |
启用视图绑定(Data Binding)
1 | kotlin项目: |
二维码扫描CameraScan / ZXing-Lite
1 | // CameraScan |
使用(TODO):
1 | ``` |
1 |
|
class InputPortNumberDialogFragment : DialogFragment() {
// 在这里定义接口,在要显示DialogFragment的Fragment中实现这个接口
interface OnInputPortReceived {
fun onInputPortReceived(input: String)
}
// 接口
private var onInputReceived: OnInputPortReceived? = null
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
//为了样式统一和兼容性,可以使用 V7 包下的 AlertDialog.Builder
val builder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
// 设置主题的构造方法
val inflater: LayoutInflater = requireActivity().getLayoutInflater()
val view: View = inflater.inflate(R.layout.fragment_input_dialog, null)
builder.setView(view)
.setMessage("请输入端口号(输入0默认54300):")
.setPositiveButton("确定") { dialog, which ->
val et = view.findViewById<EditText>(R.id.inputEditText)
var portInput:String = et.text.toString()
if (! et.text.isEmpty()) {
if (portInput.equals("0")){
portInput = "54300"
}
// 调用接口
onInputReceived?.onInputPortReceived(portInput)
dismiss() // 关闭对话框
}
}
.setNegativeButton("取消", null)
return builder.create()
}
// 接收从Fragment中传过来的接口
fun setOnInputListener(listener: OnInputPortReceived) {
onInputReceived = listener
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_input_dialog, container, false)
}
companion object {
const val TAG = "getPortDialog"
}
}
1 |
|
package cn.rmshadows.textsend.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import cn.rmshadows.textsend.R
import cn.rmshadows.textsend.databinding.FragmentServerBinding
import cn.rmshadows.textsend.viewmodels.ServerFragmentViewModel
import cn.rmshadows.textsend.viewmodels.TextsendViewModel
import kotlinx.coroutines.launch
import utils.Constant
import java.util.LinkedList
/**
A simple [Fragment] subclass as the second destination in the navigation.
*/
class ServerFragment : Fragment(), InputPortNumberDialogFragment.OnInputPortReceived,
InputIpAddressDialogFragment.OnInputIpReceived {
private var _binding: FragmentServerBinding? = null
private val TAG = Constant.TAG// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private lateinit var adapter: ArrayAdapter// https://developer.android.com/codelabs/basic-android-kotlin-training-shared-viewmodel?hl=zh-cn#4
private val tsviewModel: TextsendViewModel by activityViewModels()
private lateinit var viewModel: ServerFragmentViewModel// 实现接口
override fun onInputIpReceived(input: String) {val oips = viewModel.uiState.value.netIps oips.removeLast() oips.add(input) oips.add(viewModel.CUSTOM_INPUT_FLAG) viewModel.update(input, null, oips, null, null)
}
override fun onInputPortReceived(input: String) {
viewModel.update(null, input, null, null, null)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentServerBinding.inflate(inflater, container, false) tsviewModel.update(true, null, null) viewModel = ViewModelProvider(this).get(ServerFragmentViewModel::class.java) return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) binding.serverStartBtn.setOnLongClickListener { // 长按修改端口号 val df = InputPortNumberDialogFragment() // 传入接口实现 df.setOnInputListener(this) df.show(childFragmentManager, InputPortNumberDialogFragment.TAG) true }
}
override fun onDestroyView() {
super.onDestroyView() _binding = null
}
}1
2
`repeatOnLifecycle(Lifecycle.State.STARTED)`报错`The repeatOnLifecycle API should be used with viewLifecycleOwner`lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { binding.clientIpAddress.setText(it.serverIp) binding.clientPort.setText(it.serverPort.toString()) } } }
1
2
解决:`lifecycleScope.launch`=>`viewLifecycleOwner.lifecycleScope.launch`viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { binding.clientIpAddress.setText(it.serverIp) binding.clientPort.setText(it.serverPort.toString()) } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Kotlin
## Kotlin类变量
>https://www.baeldung.com/kotlin/companion-object
>
>https://medium.com/@ansujain/kotlin-how-to-create-static-members-for-class-543d0f126f7c
```kotlin
class ClassName {
companion object {
const val propertyName: String = "Something..."
fun funName() {
//...
}
}
}
class ClassName {
companion object {
const val propertyName: String = "Something..."
fun funName() {
//...
}
}
}
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !