a
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# Built application files
|
||||
*.apk
|
||||
*.ap_
|
||||
*.aab
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
release/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/gradle.xml
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/dictionaries
|
||||
.idea/libraries
|
||||
# Android Studio 3 in .gitignore file.
|
||||
.idea/caches
|
||||
.idea/modules.xml
|
||||
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
||||
.idea/navEditor.xml
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
#*.keystore
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
# google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Version control
|
||||
vcs.xml
|
||||
misc.xml
|
||||
|
||||
# lint
|
||||
lint/intermediates/
|
||||
lint/generated/
|
||||
lint/outputs/
|
||||
lint/tmp/
|
||||
# lint/reports/
|
||||
@@ -0,0 +1,47 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
compileSdk 32
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.fastjetpack"
|
||||
minSdk 29
|
||||
targetSdk 32
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
viewBinding {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation project(path: ':base')
|
||||
|
||||
implementation("com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-ktx:2.0.2")
|
||||
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
|
||||
|
||||
def nav_version = "2.3.5"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.aisier">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
|
||||
<application
|
||||
android:name=".App"
|
||||
android:icon="@mipmap/icon_android"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".ui.SecondActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.aisier
|
||||
|
||||
import com.aisier.architecture.base.BaseApp
|
||||
import com.ldlywt.colorful.ColorThemeConfig
|
||||
import com.ldlywt.colorful.initColorful
|
||||
|
||||
class App : BaseApp() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
val colorThemeConfig = ColorThemeConfig(
|
||||
useDarkTheme = true,
|
||||
translucent = false,
|
||||
customTheme = R.style.Theme_Red
|
||||
)
|
||||
initColorful(this, colorThemeConfig)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.aisier.bean
|
||||
|
||||
data class User(
|
||||
val admin: Boolean?,
|
||||
val chapterTops: List<Any>?,
|
||||
val email: String?,
|
||||
val icon: String?,
|
||||
val id: Int?,
|
||||
val nickname: String?,
|
||||
val publicName: String?,
|
||||
val username: String?
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.aisier.bean
|
||||
|
||||
/**
|
||||
* author : wutao
|
||||
* time : 2020/01/01
|
||||
* desc :
|
||||
* version: 1.0
|
||||
*/
|
||||
class WxArticleBean {
|
||||
/**
|
||||
* id : 408
|
||||
* name : 鸿洋
|
||||
* order : 190000
|
||||
* visible : 1
|
||||
*/
|
||||
var id = 0
|
||||
var name: String? = null
|
||||
var visible = 0
|
||||
|
||||
override fun toString(): String {
|
||||
return "TestBean(id=$id, name=$name, visible=$visible)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.aisier.net
|
||||
|
||||
import com.aisier.bean.User
|
||||
import com.aisier.bean.WxArticleBean
|
||||
import com.aisier.network.entity.ApiResponse
|
||||
import retrofit2.http.Field
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface ApiService {
|
||||
|
||||
@GET("wxarticle/chapters/json")
|
||||
suspend fun getWxArticle(): ApiResponse<List<WxArticleBean>>
|
||||
|
||||
@GET("abc/chapters/json")
|
||||
suspend fun getWxArticleError(): ApiResponse<List<WxArticleBean>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("user/login")
|
||||
suspend fun login(@Field("username") userName: String, @Field("password") passWord: String): ApiResponse<User?>
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "https://wanandroid.com/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.aisier.net
|
||||
|
||||
import com.aisier.network.base.BaseRetrofitClient
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
object RetrofitClient : BaseRetrofitClient() {
|
||||
|
||||
val service by lazy { getService(ApiService::class.java, ApiService.BASE_URL) }
|
||||
|
||||
override fun handleBuilder(builder: OkHttpClient.Builder) = Unit
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.aisier.net
|
||||
|
||||
import com.aisier.bean.User
|
||||
import com.aisier.bean.WxArticleBean
|
||||
import com.aisier.network.base.BaseRepository
|
||||
import com.aisier.network.entity.ApiResponse
|
||||
|
||||
class WxArticleRepository : BaseRepository() {
|
||||
|
||||
private val mService by lazy {
|
||||
RetrofitClient.service
|
||||
}
|
||||
|
||||
suspend fun fetchWxArticleFromNet(): ApiResponse<List<WxArticleBean>> {
|
||||
return executeHttp {
|
||||
mService.getWxArticle()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun fetchWxArticleError(): ApiResponse<List<WxArticleBean>> {
|
||||
return executeHttp {
|
||||
mService.getWxArticleError()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun login(username: String, password: String): ApiResponse<User?> {
|
||||
return executeHttp {
|
||||
mService.login(username, password)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.aisier.ui
|
||||
|
||||
import com.aisier.R
|
||||
import com.aisier.architecture.base.BaseActivity
|
||||
|
||||
class MainActivity : BaseActivity(R.layout.activity_home)
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.aisier.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.aisier.R
|
||||
import com.aisier.architecture.base.BaseActivity
|
||||
import com.ldlywt.colorful.ColorTheme
|
||||
import com.ldlywt.colorful.ThemeStyle
|
||||
|
||||
class SecondActivity : BaseActivity(R.layout.activity_second) {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
findViewById<View>(R.id.bt_change_theme).setOnClickListener {
|
||||
ColorTheme().edit()
|
||||
.setDarkTheme(false)
|
||||
.setCustomThemeOverride(ThemeStyle.values().random().res)
|
||||
.applyAndRestart(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.aisier.ui.fragment
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import androidx.navigation.findNavController
|
||||
import com.aisier.R
|
||||
import com.aisier.architecture.base.BaseFragment
|
||||
import com.aisier.ui.SecondActivity
|
||||
|
||||
class MainFragment : BaseFragment(R.layout.fragment_main) {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
view.findViewById<View>(R.id.bt_api).setOnClickListener {
|
||||
view.findNavController().navigate(R.id.netListFragment)
|
||||
}
|
||||
view.findViewById<Button>(R.id.bt_save_state).setOnClickListener {
|
||||
view.findNavController().navigate(R.id.savedStateFragment)
|
||||
}
|
||||
view.findViewById<Button>(R.id.bt_change_theme).setOnClickListener {
|
||||
requireActivity().startActivity(Intent(requireActivity(), SecondActivity::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.aisier.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.asLiveData
|
||||
import com.aisier.R
|
||||
import com.aisier.architecture.base.BaseFragment
|
||||
import com.aisier.architecture.util.collectIn
|
||||
import com.aisier.architecture.util.launchFlow
|
||||
import com.aisier.architecture.util.launchWithLoading
|
||||
import com.aisier.architecture.util.launchWithLoadingAndCollect
|
||||
import com.aisier.bean.WxArticleBean
|
||||
import com.aisier.databinding.FragmentNetListBinding
|
||||
import com.aisier.network.observeState
|
||||
import com.aisier.network.toast
|
||||
import com.aisier.vm.ApiViewModel
|
||||
import com.dylanc.viewbinding.binding
|
||||
|
||||
/**
|
||||
* dev 分支去掉LiveData,使用Flow
|
||||
*/
|
||||
class NetListFragment : BaseFragment(R.layout.fragment_net_list) {
|
||||
|
||||
// navigation情况下不能用Activity的ViewModel
|
||||
private val mViewModel by viewModels<ApiViewModel>()
|
||||
private val mBinding: FragmentNetListBinding by binding()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
initData()
|
||||
initObserver()
|
||||
}
|
||||
|
||||
private fun initObserver() {
|
||||
mViewModel.uiState.collectIn(this, Lifecycle.State.STARTED) {
|
||||
onSuccess = { result: List<WxArticleBean>? ->
|
||||
showNetErrorPic(false)
|
||||
mBinding.tvContent.text = result.toString()
|
||||
}
|
||||
|
||||
onComplete = { Log.i("NetListFragment", ": onComplete") }
|
||||
|
||||
onFailed = { code, msg -> toast("errorCode: $code errorMsg: $msg") }
|
||||
|
||||
onError = { showNetErrorPic(true) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun showNetErrorPic(isShowError: Boolean) {
|
||||
mBinding.tvContent.isGone = isShowError
|
||||
mBinding.ivContent.isVisible = isShowError
|
||||
}
|
||||
|
||||
private fun initData() {
|
||||
mBinding.btnNet.setOnClickListener { requestNet() }
|
||||
|
||||
mBinding.btnNetError.setOnClickListener {
|
||||
showNetErrorPic(false)
|
||||
requestNetError()
|
||||
}
|
||||
|
||||
mBinding.btLogin.setOnClickListener {
|
||||
showNetErrorPic(false)
|
||||
login()
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestNet() = launchWithLoading(mViewModel::requestNet)
|
||||
|
||||
private fun requestNetError() = launchWithLoading(mViewModel::requestNetError)
|
||||
|
||||
/**
|
||||
* 链式调用,返回结果的处理都在一起,viewmodel中不需要创建一个livedata对象
|
||||
* 适用于不需要监听数据变化的场景
|
||||
* 屏幕旋转,Activity销毁重建,数据会消失
|
||||
*/
|
||||
private fun login() {
|
||||
launchWithLoadingAndCollect({
|
||||
mViewModel.login("FastJetpack", "FastJetpack")
|
||||
}) {
|
||||
onSuccess = {
|
||||
mBinding.tvContent.text = it.toString()
|
||||
}
|
||||
onFailed = { errorCode, errorMsg ->
|
||||
toast("errorCode: $errorCode errorMsg: $errorMsg")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Flow转变为LiveData
|
||||
*/
|
||||
private fun loginAsLiveData() {
|
||||
val loginLiveData =
|
||||
launchFlow(requestBlock = {
|
||||
mViewModel.login(
|
||||
"FastJetpack",
|
||||
"FastJetpack11"
|
||||
)
|
||||
}).asLiveData()
|
||||
|
||||
loginLiveData.observeState(this) {
|
||||
onSuccess = { mBinding.tvContent.text = it.toString() }
|
||||
onFailed =
|
||||
{ errorCode, errorMsg -> toast("errorCode: $errorCode errorMsg: $errorMsg") }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.aisier.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.aisier.R
|
||||
import com.aisier.vm.SavedStateViewModel
|
||||
|
||||
class SavedStateFragment : Fragment(R.layout.fragment_saved_state) {
|
||||
|
||||
private val stateViewModel by viewModels<SavedStateViewModel>()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
Log.i("SavedStateActivity--> ", "SavedStateViewModel: $stateViewModel")
|
||||
Log.i("SavedStateActivity--> ", "userName: ${stateViewModel.userName}")
|
||||
val value: String = stateViewModel.inputLiveData.value.toString()
|
||||
Log.i("SavedStateActivity--> ", "input text: ${value}")
|
||||
|
||||
val submit = view.findViewById<Button>(R.id.submit)
|
||||
val editText = view.findViewById<EditText>(R.id.edit_text)
|
||||
|
||||
submit.setOnClickListener {
|
||||
stateViewModel.userName = "Hello world"
|
||||
val inputText: String = editText.toString()
|
||||
stateViewModel.inputLiveData.value = inputText
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.aisier.vm
|
||||
|
||||
import com.aisier.architecture.base.BaseViewModel
|
||||
import com.aisier.bean.User
|
||||
import com.aisier.bean.WxArticleBean
|
||||
import com.aisier.net.WxArticleRepository
|
||||
import com.aisier.network.entity.ApiResponse
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* @author : wutao
|
||||
* time : 2019/08/17
|
||||
* desc :
|
||||
* version: 1.0
|
||||
</pre> *
|
||||
*/
|
||||
class ApiViewModel : BaseViewModel() {
|
||||
|
||||
private val repository by lazy { WxArticleRepository() }
|
||||
|
||||
// 使用StateFlow 替代livedata
|
||||
// val wxArticleLiveData = StateMutableLiveData<List<WxArticleBean>>()
|
||||
|
||||
private val _uiState = MutableStateFlow<ApiResponse<List<WxArticleBean>>>(ApiResponse())
|
||||
val uiState: StateFlow<ApiResponse<List<WxArticleBean>>> = _uiState.asStateFlow()
|
||||
|
||||
suspend fun requestNet() {
|
||||
_uiState.value = repository.fetchWxArticleFromNet()
|
||||
}
|
||||
|
||||
suspend fun requestNetError() {
|
||||
_uiState.value = repository.fetchWxArticleError()
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景:不需要监听数据变化
|
||||
*/
|
||||
suspend fun login(username: String, password: String): ApiResponse<User?> {
|
||||
return repository.login(username, password)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.aisier.vm
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
|
||||
|
||||
companion object {
|
||||
const val SAVE_STATE_KEY_STRING = "user_name"
|
||||
const val SAVE_STATE_KEY_LIVE_DATE = "input_livedata"
|
||||
}
|
||||
|
||||
var userName: String?
|
||||
get() = savedStateHandle.get(SAVE_STATE_KEY_STRING)
|
||||
set(value) = savedStateHandle.set(SAVE_STATE_KEY_STRING, value)
|
||||
|
||||
val inputLiveData = savedStateHandle.getLiveData<String>(SAVE_STATE_KEY_LIVE_DATE)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_graph" />
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ui.SecondActivity">
|
||||
|
||||
<Button
|
||||
android:id="@+id/bt_change_theme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="改变主题" />
|
||||
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="占位" />
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<SeekBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:progress="50" />
|
||||
|
||||
<Switch
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/app_name" />
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TimePicker
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.fragment.MainFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/bt_api"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:text="网络请求封装" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bt_save_state"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:text="数据恢复" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/bt_change_theme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:text="随机改变主题" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.fragment.NetListFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/bt_login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="登录" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_net"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="请求网络" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_net_error"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="请求网络错误" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="10dp"
|
||||
android:layout_weight="1"
|
||||
android:text="网络请求结果:" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="400dp"
|
||||
android:layout_margin="10dp"
|
||||
android:src="@mipmap/icon_net_error"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="请输入名字" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/submit"
|
||||
android:text="提交"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation 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:id="@+id/nav_graph"
|
||||
app:startDestination="@id/mainFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/mainFragment"
|
||||
android:name="com.aisier.ui.fragment.MainFragment"
|
||||
android:label="fragment_main"
|
||||
tools:layout="@layout/fragment_main">
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_netListFragment"
|
||||
app:destination="@id/netListFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_savedStateFragment"
|
||||
app:destination="@id/savedStateFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/netListFragment"
|
||||
android:name="com.aisier.ui.fragment.NetListFragment"
|
||||
android:label="fragment_net_list"
|
||||
tools:layout="@layout/fragment_net_list" />
|
||||
<fragment
|
||||
android:id="@+id/savedStateFragment"
|
||||
android:name="com.aisier.ui.fragment.SavedStateFragment"
|
||||
android:label="fragment_saved_state"
|
||||
tools:layout="@layout/fragment_saved_state" />
|
||||
</navigation>
|
||||
@@ -0,0 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">FastJetpack</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true" />
|
||||
</network-security-config>
|
||||
|
||||
Reference in New Issue
Block a user