Android实战演练(kotlin版),词汇记录APP

简介: Android实战演练(kotlin版),词汇记录APP

效果图

以下是源代码

build.gradle文件

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
}
android {
    compileSdk 32
    defaultConfig {
        applicationId "com.example.word3"
        minSdk 27
        targetSdk 32
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}
dependencies {
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    implementation 'androidx.room:room-runtime:2.1.0'
    kapt "androidx.room:room-compiler:2.1.0"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
    implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
    implementation "androidx.navigation:navigation-ui-ktx:2.5.2"
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
}

layout

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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">
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>

cell_card.xml

<?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="60dp"
    android:clickable="true"
    android:orientation="vertical">
    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="MissingConstraints">
        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/constraintLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/guideline2"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="1.0"
            android:background="?selectableItemBackground">
            <androidx.constraintlayout.widget.Guideline
                android:id="@+id/guideline2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintGuide_percent="0.8"
                app:layout_constraintHorizontal_bias="1.0"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
            <androidx.constraintlayout.widget.Guideline
                android:id="@+id/guideline4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintGuide_percent="0.15"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
            <TextView
                android:id="@+id/textViewNumber"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="1"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toStartOf="@+id/guideline4"
                app:layout_constraintHorizontal_bias="0.38"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="0.412" />
            <TextView
                android:id="@+id/textViewEnglish"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="200dp"
                android:paddingTop="20dp"
                android:text="TextView"
                android:textSize="24dp"
                app:layout_constraintBottom_toTopOf="@+id/textViewChinese"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintStart_toStartOf="@+id/guideline4"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="0.333"
                app:layout_goneMarginStart="16dp" />
            <TextView
                android:id="@+id/textViewChinese"
                android:layout_width="wrap_content"
                android:layout_height="60dp"
                android:layout_marginEnd="204dp"
                android:paddingLeft="0dp"
                android:paddingTop="40dp"
                android:text="TextView"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.072"
                app:layout_constraintStart_toStartOf="@id/textViewEnglish"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="0.878" />
            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/constraintLayout2"
                android:layout_width="83dp"
                android:layout_height="80dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintStart_toStartOf="@+id/guideline2"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_bias="1.0">
                <Switch
                    android:id="@+id/aSwitchChineseInvisible"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingStart="30dp"
                    android:paddingEnd="15dp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.444"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintVertical_bias="0.484"
                    tools:ignore="TouchTargetSizeCheck,UseSwitchCompatOrMaterialXml" />
            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.cardview.widget.CardView>
</LinearLayout>

cell_normal.xml  

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="60dp"
    android:background="#F9F9F9"
    android:clickable="true">
    <View
        android:id="@+id/divider"
        android:layout_width="2dp"
        android:layout_height="match_parent"
        android:background="?android:attr/listDivider"
        android:paddingTop="5dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@+id/constraintLayout"
        app:layout_constraintStart_toEndOf="@+id/constraintLayout"
        app:layout_constraintTop_toTopOf="parent" />
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraintLayout"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:background="@android:drawable/list_selector_background"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/guideline2"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1.0">
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0.15" />
        <TextView
            android:id="@+id/textViewNumber"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="1"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/guideline4"
            app:layout_constraintHorizontal_bias="0.38"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.412" />
        <TextView
            android:id="@+id/textViewEnglish"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="200dp"
            android:text="TextView"
            android:textSize="24dp"
            app:layout_constraintBottom_toTopOf="@+id/textViewChinese"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="@+id/guideline4"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.333"
            app:layout_goneMarginStart="16dp" />
        <TextView
            android:id="@+id/textViewChinese"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="204dp"
            android:text="TextView"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.072"
            app:layout_constraintStart_toStartOf="@id/textViewEnglish"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.878" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraintLayout2"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline2"
        app:layout_constraintTop_toTopOf="parent">
        <Switch
            android:id="@+id/aSwitchChineseInvisible"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:paddingStart="20dp"
            android:paddingEnd="15dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.444"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.484"
            tools:ignore="TouchTargetSizeCheck,UseSwitchCompatOrMaterialXml" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.8" />
</androidx.constraintlayout.widget.ConstraintLayout>

fragment_add.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/addLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AddFragment">
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="添加单词"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.485"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.135" />
    <EditText
        android:id="@+id/editTextEnglish"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="English_Word"
        android:inputType="textPersonName"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.276" />
    <EditText
        android:id="@+id/editTextChinese"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="中文"
        android:inputType="textPersonName"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.406" />
    <Button
        android:id="@+id/buttonSubmit"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Add"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

fragment_words.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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/wordsFragmentView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".WordsFragment">
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center_horizontal"
        android:layout_margin="16dp"
        android:clickable="true"
        android:elevation="8dp"
        android:src="@drawable/ic_baseline_add_24"
        tools:ignore="SpeakableTextPresentCheck" />
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

menu:

main_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/clearData"
        android:title="清空数据" />
    <item
        android:id="@+id/switchViewType"
        android:title="切换视图" />
    <item
        android:id="@+id/app_bar_search"
        android:icon="@android:drawable/ic_menu_search"
        android:title="Search"
        app:actionViewClass="androidx.appcompat.widget.SearchView"
        app:showAsAction="always" />
</menu>

navigation:

navigation.xml

<?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/navigation"
    app:startDestination="@id/wordsFragment">
    <fragment
        android:id="@+id/addFragment"
        android:name="com.example.word3.AddFragment"
        android:label="Add"
        tools:layout="@layout/fragment_add" />
    <fragment
        android:id="@+id/wordsFragment"
        android:name="com.example.word3.WordsFragment"
        android:label="Words"
        tools:layout="@layout/fragment_words">
        <action
            android:id="@+id/action_wordsFragment_to_addFragment"
            app:destination="@id/addFragment"
            app:enterAnim="@anim/nav_default_enter_anim" />
    </fragment>
</navigation>

values

ids.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="word_for_view_holder" type="id"/>
</resources>

AddFragment

import android.content.Context
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.Navigation
class AddFragment : Fragment() {
    private lateinit var buttonSubmit: Button
    private lateinit var editTextEnglish: EditText
    private lateinit var editTextChinese: EditText
    private lateinit var wordViewModel: WordViewModel
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        var view: View = inflater.inflate(R.layout.fragment_add, container, false)
        buttonSubmit = view.findViewById(R.id.buttonSubmit)
        editTextChinese = view.findViewById(R.id.editTextChinese)
        editTextEnglish = view.findViewById(R.id.editTextEnglish)
        return view
    }
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        buttonSubmit.isEnabled = false
        editTextEnglish.requestFocus()
        wordViewModel= ViewModelProvider(requireActivity()).get(WordViewModel::class.java)
        val imm: InputMethodManager =
            requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.showSoftInput(editTextEnglish, 0)
        editTextChinese.addTextChangedListener(mydetextWatcher())
        editTextEnglish.addTextChangedListener(mydetextWatcher())
        buttonSubmit.setOnClickListener {
            val english:String=editTextEnglish.text.toString().trim()
            val chinese:String=editTextChinese.text.toString().trim()
            val word:Word= Word(english,chinese,false)
            wordViewModel.insertWords(word)
            val navController: NavController = Navigation.findNavController(it)
            navController.navigateUp()
            val imm:InputMethodManager= requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.hideSoftInputFromWindow(it.windowToken,0)
        }
    }
    inner class mydetextWatcher : TextWatcher {
        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
            val english: String = editTextEnglish.text.toString().trim()
            val chinese: String = editTextChinese.text.toString().trim()
            buttonSubmit.isEnabled = english.isNotEmpty() && chinese.isNotEmpty()
        }
        override fun afterTextChanged(p0: Editable?) {
        }
    }
}

MainActivity

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.NavigationUI
class MainActivity : AppCompatActivity() {
    private lateinit var navController:NavController
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
      navController=supportFragmentManager.findFragmentById(R.id.fragment)?.findNavController() as NavController
       NavigationUI.setupActionBarWithNavController(this,navController)
    }
    override fun onSupportNavigateUp(): Boolean {
        navController.navigateUp()
        return super.onSupportNavigateUp()||findNavController(R.id.fragment).navigateUp()
    }
}

MyAdapter

import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Switch
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
class MyAdapter(var useCardView:Boolean,var wordViewModel: WordViewModel) :androidx.recyclerview.widget.ListAdapter<Word,MyAdapter.ViewHolder>(diffCallback) {
    companion object{
        val diffCallback=object :DiffUtil.ItemCallback<Word>(){
            override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean {
                return oldItem.id==newItem.id
            }
            override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean {
                return (oldItem.word == newItem.word &&
                        oldItem.chineseMeaning == newItem.chineseMeaning &&
                        oldItem.isChineseInvisible == newItem.isChineseInvisible)
            }
        }
    }
    override fun onViewAttachedToWindow(holder: ViewHolder) {
        super.onViewAttachedToWindow(holder)
        holder.textViewNumber.text=(holder.absoluteAdapterPosition +1).toString()
    }
    inner class ViewHolder(view:View):RecyclerView.ViewHolder(view){
        val aSwitchChineseInvisible:Switch=view.findViewById(R.id.aSwitchChineseInvisible)
        var textViewNumber:TextView=view.findViewById(R.id.textViewNumber)
        var textViewEnglish:TextView=view.findViewById(R.id.textViewEnglish)
        var textViewChinese:TextView=view.findViewById(R.id.textViewChinese)
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        var layoutInflater:LayoutInflater=LayoutInflater.from(parent.context)
        var itemView:View = if(useCardView){
            layoutInflater.inflate(R.layout.cell_card,parent,false)
        }else{
            layoutInflater.inflate(R.layout.cell_normal,parent,false)
        }
        val holder: ViewHolder =ViewHolder(itemView)
        holder.itemView.setOnClickListener {
            var uri:Uri= Uri.parse("https://m.youdao.com/dict?le=eng&q="+holder.textViewEnglish.text)
            var intent:Intent= Intent(Intent.ACTION_VIEW)
            intent.setData(uri)
            holder.itemView.context.startActivities(arrayOf(intent))
        }
        holder.aSwitchChineseInvisible.setOnCheckedChangeListener { compoundButton, b ->
            var word:Word=holder.itemView.getTag(R.id.word_for_view_holder) as Word
            if (b){
                word.isChineseInvisible=true
                holder.textViewChinese.visibility=View.GONE
                wordViewModel.updateWords(word)
            }else{
                word.isChineseInvisible=false
                holder.textViewChinese.visibility=View.VISIBLE
                wordViewModel.updateWords(word)
            }
        }
        return holder
    }
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        var word:Word=getItem(position)
        holder.itemView.setTag(R.id.word_for_view_holder,word)
        holder.textViewNumber.text= (position+1).toString()
        holder.textViewEnglish.text=word.word
        holder.textViewChinese.text=word.chineseMeaning
        if (word.isChineseInvisible){
            holder.textViewChinese.visibility=View.GONE
            holder.aSwitchChineseInvisible.isChecked=true
        }else{
            holder.textViewChinese.visibility=View.VISIBLE
            holder.aSwitchChineseInvisible.isChecked=false
        }
    }
}

MyApplication

import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
class MyApplication:Application() {
    companion object{
        @SuppressLint("StaticFieldLeak")
        lateinit var context: Context
    }
    override fun onCreate() {
        super.onCreate()
        context=applicationContext
    }
}

Word

@Entity
data class Word (var word: String,var chineseMeaning:String,var isChineseInvisible:Boolean){
    @PrimaryKey(autoGenerate = true)
    var id:Int=0
}

WordDao

import androidx.lifecycle.LiveData
import androidx.room.*
@Dao
interface WordDao {
    @Insert
    fun insertWords( vararg word: Word)
    @Update
    fun updateWords(vararg word: Word)
    @Delete
    fun deleteWords(vararg word: Word)
    @Query("DELETE FROM WORD")
    fun deleteAllWords()
    @Query("SELECT * FROM WORD ORDER BY ID DESC")
    fun getAllWordsLive():LiveData<List<Word>>
    @Query("SELECT * FROM WORD WHERE word LIKE:patten ORDER BY ID DESC")
    fun findWordsWithPatten(patten:String):LiveData<List<Word>>
}

WordDatabase

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database( version = 3, entities = [Word::class],exportSchema = false)
abstract class WordDatabase: RoomDatabase() {
    companion object {
        private var instance: WordDatabase? = null
        @Synchronized
        fun getWordDatabase(context: Context): WordDatabase {
            instance?.let {
                return it
            }
            return Room.databaseBuilder(
                context.applicationContext,
                WordDatabase::class.java, "word_database"
            ).allowMainThreadQueries().fallbackToDestructiveMigration()
                .build()
                .apply {
                    instance = this
                }
        }
    }
    abstract fun getWordDao():WordDao
}

WordRepository

import android.os.AsyncTask
import androidx.lifecycle.LiveData
class WordRepository {
   lateinit var wordDao: WordDao
    lateinit var allWordsLive: LiveData<List<Word>>
    init {
        val wordDatabase:WordDatabase=WordDatabase.getWordDatabase(MyApplication.context)
        wordDao=wordDatabase.getWordDao()
        allWordsLive=wordDao.getAllWordsLive()
    }
    fun findWordsWithPatten(patten:String): LiveData<List<Word>>{
        return wordDao.findWordsWithPatten("%"+patten+"%")
    }
    fun insertWords(vararg p0: Word?){
        InsertAsyncTask(wordDao).execute(*p0)
    }
    fun updateWords(vararg p0: Word?){
        UpdateAsyncTask(wordDao).execute(*p0)
    }
    fun deleteWords(vararg p0: Word?){
        DeleteAsyncTask(wordDao).execute(*p0)
    }
    fun deleteAllWords(vararg p0: Word?){
        DeleteAllAsyncTask(wordDao).execute()
    }
    companion object {
        class InsertAsyncTask internal constructor(var wordDao: WordDao) :
            AsyncTask<Word, Void, Void?>() {
            override fun doInBackground(vararg p0: Word?): Void? {
                wordDao.insertWords(*p0 as Array<out Word>)
                return null
            }
        }
        class UpdateAsyncTask internal constructor(var wordDao: WordDao) :
            AsyncTask<Word, Void, Void?>() {
            override fun doInBackground(vararg p0: Word?): Void? {
                wordDao.updateWords(*p0 as Array<out Word>)
                return null
            }
        }
        class DeleteAsyncTask internal constructor(var wordDao: WordDao) :
            AsyncTask<Word, Void, Void?>() {
            override fun doInBackground(vararg p0: Word?): Void? {
                wordDao.deleteWords(*p0 as Array<out Word>)
                return null
            }
        }
        class DeleteAllAsyncTask internal constructor(var wordDao: WordDao) :
            AsyncTask<Void, Void, Void?>() {
            override fun doInBackground(vararg p0: Void?): Void? {
                wordDao.deleteAllWords()
                return null
            }
        }
    }
}

WordsFragment

 

import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.view.*
import androidx.fragment.app.Fragment
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.Navigation
import androidx.recyclerview.widget.*
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
class WordsFragment : Fragment() {
    private lateinit var wordViewModel: WordViewModel
    private lateinit var recyclerView: RecyclerView
    private lateinit var myAdapter1: MyAdapter
    private lateinit var myAdapter2: MyAdapter
    private lateinit var floatingActionButton: FloatingActionButton
    private lateinit var filteredWords: LiveData<List<Word>>
    val VIEW_TYPE_SHP:String="view_type_shp"
    val IS_USING_CARD_VIEW:String="is_using_card_view"
    private lateinit var allWords:List<Word>
    lateinit var dividerItemDecoration: DividerItemDecoration
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        wordViewModel = ViewModelProvider(this).get(WordViewModel::class.java)
        myAdapter1 = MyAdapter(false, wordViewModel)
        myAdapter2 = MyAdapter(true, wordViewModel)
    }
   inner class defaultItemAnimator:DefaultItemAnimator(){
        override fun onAnimationFinished(viewHolder: RecyclerView.ViewHolder) {
            super.onAnimationFinished(viewHolder)
            var linearLayoutManager:LinearLayoutManager=recyclerView.layoutManager as LinearLayoutManager
            if (linearLayoutManager!=null){
                var firstPosition:Int=linearLayoutManager.findFirstVisibleItemPosition()
                var lastPosition:Int=linearLayoutManager.findLastVisibleItemPosition()
                for (i in firstPosition until lastPosition+1){
                   var holder: MyAdapter.ViewHolder=recyclerView.findViewHolderForAdapterPosition(i) as MyAdapter.ViewHolder
                    if (holder!=null){
                        holder.textViewNumber.text= (i+1).toString()
                    }
                }
            }
        }
    }
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        recyclerView.itemAnimator=defaultItemAnimator()
        var shp=requireActivity().getSharedPreferences(VIEW_TYPE_SHP,Context.MODE_PRIVATE)
        var viewType:Boolean=shp.getBoolean(IS_USING_CARD_VIEW,false)
        dividerItemDecoration= DividerItemDecoration(requireActivity(),DividerItemDecoration.VERTICAL)
        if (viewType){
            recyclerView.adapter=myAdapter2
        }else{
            recyclerView.adapter=myAdapter1
            recyclerView.addItemDecoration(dividerItemDecoration)
        }
        filteredWords=wordViewModel.allWordsLive
        filteredWords.observe(requireActivity(), Observer { count ->
            var temp:Int=myAdapter1.itemCount
            allWords=count
            if (temp!=count.size){
                if (temp<count.size)
                    recyclerView.smoothScrollBy(0,-200)
                myAdapter1.submitList(count)
                myAdapter2.submitList(count)
            }
        })
        ItemTouchHelper(object :ItemTouchHelper.Callback(){
            override fun getMovementFlags(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder
            ): Int {
                return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN,ItemTouchHelper.START or ItemTouchHelper.END)
            }
            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                Toast.makeText(requireActivity(),"慢一点",Toast.LENGTH_SHORT).show()
                var wordFrom:Word=allWords.get(viewHolder.adapterPosition)
                var wordTo:Word=allWords.get(target.adapterPosition)
                var idTemp:Int=wordFrom.id
                wordFrom.id=wordTo.id
                wordTo.id=idTemp
                wordViewModel.updateWords(wordFrom,wordTo)
                myAdapter1.notifyItemMoved(viewHolder.adapterPosition,target.adapterPosition)
                myAdapter2.notifyItemMoved(viewHolder.adapterPosition,target.adapterPosition)
                return false
            }
            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                var wordToDelete:Word=allWords.get(viewHolder.adapterPosition)
                wordViewModel.deleteWords(wordToDelete)
                Snackbar.make(requireActivity().findViewById(R.id.wordsFragmentView),"删除了一个词汇",Snackbar.LENGTH_SHORT)
                    .setAction("撤销",View.OnClickListener {
                        wordViewModel.insertWords(wordToDelete)
                    })
                    .show()
            }
        }).attachToRecyclerView(recyclerView)
        floatingActionButton.setOnClickListener {
            var navController: NavController = Navigation.findNavController(it)
            navController.navigate(R.id.action_wordsFragment_to_addFragment)
        }
    }
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        var view:View=inflater.inflate(R.layout.fragment_words, container, false)
        recyclerView = view.findViewById(R.id.recyclerView)
        floatingActionButton=view.findViewById(R.id.floatingActionButton)
        recyclerView.layoutManager = LinearLayoutManager(activity)
        recyclerView.adapter = myAdapter1
        setHasOptionsMenu(true)
        return view
    }
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
       super.onCreateOptionsMenu(menu,inflater)
        inflater?.inflate(R.menu.main_menu,menu)
       var searchView:SearchView= menu.findItem(R.id.app_bar_search).actionView as SearchView
        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String?): Boolean {
                return false
            }
            override fun onQueryTextChange(newText: String): Boolean {
                    var patten: String = newText.trim()
                    filteredWords.removeObservers(requireActivity())
                    filteredWords = wordViewModel.findWordsWithPatten(patten)
                    filteredWords.observe(requireActivity(), Observer { count ->
                        var temp = myAdapter1.itemCount
                        allWords=count
                        if (temp != count.size) {
                            myAdapter1.submitList(count)
                            myAdapter2.submitList(count)
                        }
                    })
                return false
            }
        })
    }
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            R.id.clearData->AlertDialog.Builder(requireActivity()).apply {
                setTitle("清空数据")
                setPositiveButton("确定"){dialog,which->wordViewModel.deleteAllWords()}
                setNegativeButton("取消"){dialog,which->}
                show()
            }
            R.id.switchViewType->{ var shp=requireActivity().getSharedPreferences(VIEW_TYPE_SHP,Context.MODE_PRIVATE)
                var viewType:Boolean=shp.getBoolean(IS_USING_CARD_VIEW,false)
                var editor:SharedPreferences.Editor=shp.edit()
                if (viewType){
                    recyclerView.adapter=myAdapter1
                    recyclerView.addItemDecoration(dividerItemDecoration)
                    editor.putBoolean(IS_USING_CARD_VIEW,false)
                }else{
                    recyclerView.adapter=myAdapter2
                    recyclerView.removeItemDecoration(dividerItemDecoration)
                    editor.putBoolean(IS_USING_CARD_VIEW,true)
                }
                editor.apply()
            }
        }
        return super.onOptionsItemSelected(item)
    }
}

WordViewModel

import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
class WordViewModel: ViewModel() {
    lateinit var wordRepository: WordRepository
    lateinit var allWordsLive: LiveData<List<Word>>
    init {
        wordRepository= WordRepository()
        allWordsLive=wordRepository.allWordsLive
    }
    fun findWordsWithPatten(patten:String): LiveData<List<Word>>{
        return wordRepository.findWordsWithPatten("%"+patten+"%")
    }
    fun insertWords(vararg p0: Word?){
        wordRepository.insertWords(*p0)
    }
    fun updateWords(vararg p0: Word?){
        wordRepository.updateWords(*p0)
    }
    fun deleteWords(vararg p0: Word?){
        wordRepository.deleteWords(*p0)
    }
    fun deleteAllWords(vararg p0: Word?){
        wordRepository.deleteAllWords()
    }
}
目录
相关文章
|
25天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
26天前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【4月更文挑战第2天】随着移动应用开发的不断进步,开发者们寻求更流畅、高效的用户体验。在Android平台上,Kotlin语言凭借其简洁性和功能性赢得了开发社区的广泛支持。特别是Kotlin协程,作为一种轻量级的并发处理方案,使得异步编程变得更加简单和直观。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何将其应用于Android开发中,以提高应用性能和响应能力。通过实际案例分析,我们将展示协程如何简化复杂任务,优化资源管理,并为最终用户提供更加流畅的体验。
|
27天前
|
Java Android开发 开发者
构建高效Android应用:Kotlin协程的实践与优化
在响应式编程范式日益盛行的今天,Kotlin协程作为一种轻量级的线程管理解决方案,为Android开发带来了性能和效率的双重提升。本文旨在探讨Kotlin协程的核心概念、实践方法及其在Android应用中的优化策略,帮助开发者构建更加流畅和高效的应用程序。通过深入分析协程的原理与应用场景,结合实际案例,本文将指导读者如何优雅地解决异步任务处理,避免阻塞UI线程,从而优化用户体验。
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
在开发高性能的Android应用时,选择合适的编程语言至关重要。近年来,Kotlin因其简洁性和功能性受到开发者的青睐,但其性能是否与传统的Java相比有所不足?本文通过对比分析Kotlin与Java在Android平台上的运行效率,揭示二者在编译速度、运行时性能及资源消耗方面的具体差异,并探讨在实际项目中如何做出最佳选择。
18 4
|
1天前
|
缓存 监控 Android开发
Android 应用性能优化实战
【4月更文挑战第27天】 在竞争激烈的移动应用市场中,性能优越的应用更能吸引和保留用户。针对Android平台,本文将深入探讨影响应用性能的关键因素,并提供一系列实用的优化策略。我们将从内存管理、UI渲染、多线程处理以及电池使用效率等方面入手,通过具体案例分析如何诊断常见问题,并给出相应的解决方案。文中所提技巧旨在帮助开发者构建更加流畅、高效的Android应用。
8 2
|
2天前
|
安全 数据处理 Android开发
构建高效Android应用:Kotlin协程的实践之路
【4月更文挑战第26天】 在面对现代Android开发时,性能优化和流畅的用户体验成为了开发者们追求的目标。Kotlin作为一种现代化的编程语言,通过其协程特性为Android应用带来了前所未有的并发处理能力。本文将深入探讨如何利用Kotlin协程提升Android应用的响应性和效率,同时保持代码的简洁性。我们将从协程的基础概念出发,逐步揭示如何在实际应用中运用这些强大的工具,以及它们如何改善应用架构和用户交互体验。
|
4天前
|
移动开发 Java Android开发
构建高效Android应用:采用Kotlin协程优化网络请求
【4月更文挑战第24天】 在移动开发领域,尤其是对于Android平台而言,网络请求是一个不可或缺的功能。然而,随着用户对应用响应速度和稳定性要求的不断提高,传统的异步处理方式如回调地狱和RxJava已逐渐显示出局限性。本文将探讨如何利用Kotlin协程来简化异步代码,提升网络请求的效率和可读性。我们将深入分析协程的原理,并通过一个实际案例展示如何在Android应用中集成和优化网络请求。
|
4天前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin协程的优势与实践
【4月更文挑战第24天】随着移动开发技术的不断演进,提升应用性能和用户体验已成为开发者的核心任务。在Android平台上,Kotlin语言凭借其简洁性和功能性成为主流选择之一。特别是Kotlin的协程功能,它为异步编程提供了一种轻量级的解决方案,使得处理并发任务更加高效和简洁。本文将深入探讨Kotlin协程在Android开发中的应用,通过实际案例分析协程如何优化应用性能,以及如何在项目中实现协程。
|
6天前
|
测试技术 Android开发
Android App获取不到pkgInfo信息问题原因
Android App获取不到pkgInfo信息问题原因
14 0
|
10天前
|
移动开发 Android开发 开发者
构建高效Android应用:采用Kotlin进行内存优化的策略
【4月更文挑战第18天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,由于设备和版本的多样性,确保应用流畅运行且占用资源少是一大挑战。本文将探讨使用Kotlin语言开发Android应用时,如何通过内存优化来提升应用性能。我们将从减少不必要的对象创建、合理使用数据结构、避免内存泄漏等方面入手,提供实用的代码示例和最佳实践,帮助开发者构建更加高效的Android应用。