gpt4 book ai didi

android - 如何在Android中从Fragment传递Context对象?

转载 作者:行者123 更新时间:2023-12-02 13:03:23 24 4
gpt4 key购买 nike

我最近学习了SQLite,并且了解MVVM的基本知识。试图使用这两个构建一个简单的记事本应用程序。为了创建使用SQLiteOpenHelper类的数据库,我知道我们需要一个Context对象。我在如何将Context对象从Fragment传递到Repository类时遇到了麻烦。这些是类:
MainActivity.kt

package com.kotlin.thenotepadapplication.view

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.appcompat.widget.Toolbar
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.kotlin.thenotepadapplication.R

class MainActivity : AppCompatActivity(), View.OnClickListener {

private lateinit var activityMainToolbar: Toolbar
private lateinit var activityMainRecyclerView: RecyclerView
private lateinit var activityMainConstraintLayout: ConstraintLayout
private lateinit var activityMainFragmentConstraintLayout: ConstraintLayout
private lateinit var activityMainFloatingActionButton: FloatingActionButton

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

initializeWidgets()
initializeToolbar(R.string.app_name)
setOnClickListenerMethod()
}

/**Governing method that overlooks all fragment transactions taking place
* First, it makes the current ConstraintLayout invisible while bringing the ConstraintLayout designated for the fragments into view.
* Next, depending on the function to be performed, it then segregates the work functions in:
* 1. the initializeToolbar() method
* 2. the performFragmentTransactionMethod() method*/
private fun initializeFragmentTransactions(fragment: Fragment, toolbarTitle: Int) {
activityMainConstraintLayout.visibility = View.INVISIBLE
activityMainFragmentConstraintLayout.visibility = View.VISIBLE
initializeToolbar(toolbarTitle)
performFragmentTransactionMethod(fragment)
}

/**The performFragmentTransactionMethod() is charged simply with changing the current fragment that's present.
* It takes in the required fragment to be attached as an argument and then changes to it.*/
private fun performFragmentTransactionMethod(fragment: Fragment) {
val fragmentManager: FragmentManager = supportFragmentManager
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.add(R.id.activity_main_fragment_constraint_layout, fragment)
fragmentTransaction.commit()
}

/**Method to initialize the widgets present in the View*/
private fun initializeWidgets() {
activityMainToolbar = findViewById(R.id.activity_main_toolbar_layout)
activityMainRecyclerView = findViewById(R.id.activity_main_recycler_view)
activityMainFloatingActionButton = findViewById(R.id.activity_main_floating_action_button)
activityMainConstraintLayout = findViewById(R.id.activity_main_constraint_layout)
activityMainFragmentConstraintLayout =
findViewById(R.id.activity_main_fragment_constraint_layout)
}

/**Method to initialize the Activity toolbar*/
private fun initializeToolbar(toolbarTitle: Int) {
setSupportActionBar(activityMainToolbar)
supportActionBar!!.setTitle(toolbarTitle)
}

/**Method to set the onClickListeners for all the required views in the application.*/
private fun setOnClickListenerMethod() {
activityMainFloatingActionButton.setOnClickListener(this)
}

/**Method to intercept all the clicks performed in the current View*/
override fun onClick(view: View?) {
if (view == activityMainFloatingActionButton) {
val addEditFragment = AddEditFragment()
val titleString: Int = R.string.new_note_string
initializeFragmentTransactions(addEditFragment, titleString)
}
}

/**Function that checks what to when the back button is pressed.
* If any fragment is active, it simply means that the activityMainFragmentConstraintLayout is invisible.
* Therefore, pressing the back button should bring the user back to the home page of the application.
* In the other case, i.e., the user is present on the main page, the app should exit. */
override fun onBackPressed() {
if (activityMainConstraintLayout.visibility == View.INVISIBLE) {
activityMainFragmentConstraintLayout.visibility = View.INVISIBLE
activityMainConstraintLayout.visibility = View.VISIBLE
initializeToolbar(R.string.app_name)
} else {
super.onBackPressed()
}
}

companion object {
private const val TAG = "MainActivity"
}
}
AddEditFragment.kt
package com.kotlin.thenotepadapplication.view

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.kotlin.thenotepadapplication.R
import com.kotlin.thenotepadapplication.model.NotepadEntryPOJO
import com.kotlin.thenotepadapplication.viewmodel.MainActivityViewModel
import java.text.SimpleDateFormat
import java.util.*

class AddEditFragment : Fragment(), View.OnClickListener {

private lateinit var fragmentAddEditSaveButton: Button
private lateinit var fragmentAddEditTitleTextView: TextView
private lateinit var fragmentAddEditSubtitleTextView: TextView
private lateinit var mainActivityViewModel: MainActivityViewModel

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view: View = inflater.inflate(R.layout.fragment_add_edit, container, false)
initializeWidgets(view)
setOnClickListenerMethod()
return view
}

private fun initiateSaveMethod(notepadEntryPOJO: NotepadEntryPOJO) {
Log.d(TAG, "initiateSaveMethod: Started")
mainActivityViewModel.insertDataIntoDatabase(notepadEntryPOJO).observe(this, {
Toast.makeText(context, it.toString(), Toast.LENGTH_SHORT).show()
})
}

/**OnClick method that handles all the clicks performed in the current view.*/
override fun onClick(view: View?) {
if (view == fragmentAddEditSaveButton) {
val titleString: String = fragmentAddEditTitleTextView.text.toString()
val subtitleString: String = fragmentAddEditSubtitleTextView.text.toString()
val dateString: String = getDateMethod()
initiateSaveMethod(NotepadEntryPOJO(titleString, subtitleString, dateString))
}
}

/**Method to get the date using the SimpleDateFormat class*/
private fun getDateMethod(): String {
return SimpleDateFormat("dd-MM-yy", Locale.US).format(Date())
}

/**Method to initializeWidgets present in the Fragment.*/
private fun initializeWidgets(view: View) {
fragmentAddEditSaveButton = view.findViewById(R.id.add_edit_fragment_save_button)
fragmentAddEditTitleTextView = view.findViewById(R.id.add_edit_fragment_title_edit_text)
fragmentAddEditSubtitleTextView =
view.findViewById(R.id.add_edit_fragment_subtitle_edit_text)
mainActivityViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
}

/**Method to intercept all the clicks performed in the current View*/
private fun setOnClickListenerMethod() {
fragmentAddEditSaveButton.setOnClickListener(this)
}

companion object {
private const val TAG = "AddEditFragment"
}

}
MainActivityViewModel.kt
package com.kotlin.thenotepadapplication.viewmodel

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.kotlin.thenotepadapplication.model.NotepadEntryPOJO
import com.kotlin.thenotepadapplication.repository.DatabaseRepository

class MainActivityViewModel : ViewModel() {
private val databaseRepository: DatabaseRepository = DatabaseRepository()

fun insertDataIntoDatabase(notepadEntryPOJO: NotepadEntryPOJO): MutableLiveData<Long> {
databaseRepository.insertMethod(notepadEntryPOJO)
return databaseRepository.returnMutableLiveData()
}
}
DatabaseRepository.kt
package com.kotlin.thenotepadapplication.repository

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.provider.BaseColumns
import androidx.lifecycle.MutableLiveData
import com.kotlin.thenotepadapplication.model.NotepadContract
import com.kotlin.thenotepadapplication.model.NotepadEntryDatabaseHelper
import com.kotlin.thenotepadapplication.model.NotepadEntryPOJO

/**The DatabaseRepository class is tasked with managing all the Database operations.
* The repository class isn't usually included with the MVVM architecture, but it recommended for best practices.
* The ViewModel will be communicating with this Repository class to perform all the operations.*/
class DatabaseRepository {
private val notepadEntryDatabaseHelper: NotepadEntryDatabaseHelper = NotepadEntryDatabaseHelper()

private val rowMutableLiveData: MutableLiveData<Long> = MutableLiveData()

/**Method used for performing inserting values into the database */
fun insertMethod(notepadEntryPOJO: NotepadEntryPOJO) {
val sqliteDatabase: SQLiteDatabase = notepadEntryDatabaseHelper.writableDatabase
val insertValues: ContentValues = ContentValues().apply {
put(NotepadContract.NotepadEntry.COLUMN_TITLE, notepadEntryPOJO.title)
put(NotepadContract.NotepadEntry.COLUMN_SUBTITLE, notepadEntryPOJO.subtitle)
put(NotepadContract.NotepadEntry.COLUMN_DATE, notepadEntryPOJO.date)
}

/*Insert queries usually return a long value signifying the row in which the value has been inserted.
* The calling method for the insertMethod() will display this returned value as a Toast.*/
val rowID: Long = sqliteDatabase.insert(
NotepadContract.NotepadEntry.TABLE_NAME,
null,
insertValues
)

rowMutableLiveData.postValue(rowID)
}

fun returnMutableLiveData(): MutableLiveData<Long>{
return rowMutableLiveData
}

/**Method for querying all the details present in the database.
* The details are extracted in a cursor format that is sent to the cursorParseMethod() for extraction.
* The cursorParseMethod() then returns an ArrayList of type NotepadEntryPOJO to this current method.
* This method then, promptly, returns the same ArrayList.*/
fun queryMethod(): ArrayList<NotepadEntryPOJO> {
val sqLiteDatabase: SQLiteDatabase = notepadEntryDatabaseHelper.readableDatabase
val sortOrder = "${BaseColumns._ID} DESC"

/*The projection specifies the exact columns from which we want to extract data from the database.
* In this case, the column ID is being omitted as it isn't quite usable in the Views.*/
val projection = arrayOf(
NotepadContract.NotepadEntry.TABLE_NAME,
NotepadContract.NotepadEntry.COLUMN_TITLE,
NotepadContract.NotepadEntry.COLUMN_DATE
)

/*The cursor object extract only the columns as specified in the projection array.
* In this case, it extracts all the columns with the exception of the ID column.
* The ID column is being used only for sorting the values into a descending order.*/
val cursor: Cursor = sqLiteDatabase.query(
NotepadContract.NotepadEntry.TABLE_NAME,
projection,
null,
null,
null,
null,
sortOrder
)

return cursorParseMethod(cursor)
}

/**The cursorParseMethod() takes an argument of type Cursor.
* It queries this cursor object and extract all the files into a separate ArrayList.
* This ArrayList is sent back to the query method.*/
private fun cursorParseMethod(cursor: Cursor): ArrayList<NotepadEntryPOJO> {
val databaseItems: ArrayList<NotepadEntryPOJO> = ArrayList()

with(cursor) {
while (cursor.moveToNext()) {
val titleItem = getString(getColumnIndex(NotepadContract.NotepadEntry.COLUMN_TITLE))
val subtitleItem =
getString(getColumnIndex(NotepadContract.NotepadEntry.COLUMN_SUBTITLE))
val dateItem = getString(getColumnIndex(NotepadContract.NotepadEntry.COLUMN_DATE))
databaseItems.add(NotepadEntryPOJO(titleItem, subtitleItem, dateItem))
}
}

return databaseItems
}
}
NotepadEntryDatabaseHelper.kt
package com.kotlin.thenotepadapplication.model

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

/**The DatabaseHelper class used for initializing for performing initial database operations*/
class NotepadEntryDatabaseHelper(context: Context) : SQLiteOpenHelper(
context,
NotepadContract.DATABASE_NAME,
null,
NotepadContract.DATABASE_VERSION
) {

/**The onCreate method is used for initially creating the database.*/
override fun onCreate(db: SQLiteDatabase?) {
db!!.execSQL(NotepadContract.SQLITE_CREATE_ENTRY)
}

/**The onUpgrade is used when we want to upgrade database.
* Usually upgrade refers to when we add more columns or remove them and other such operations.*/
override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {

}

}
目前,该行:
 private val notepadEntryDatabaseHelper: NotepadEntryDatabaseHelper = NotepadEntryDatabaseHelper()
正在显示错误,因为那里没有传递Context对象。我想知道如何才能做到这一点。我考虑过在DatabaseRepository.kt类中创建一个方法,该方法将在每次需要时初始化对象,即在insertMethod()和queryMethod()的开头初始化对象。
但是我对此也感到担心,特别是这是否会导致创建过多的对象?
我想提及的另一件事是,我尝试通过为MainActivityViewModel类创建构造函数来传递Context对象。但是它不断引起错误,即:
java.lang.RuntimeException: Cannot create an instance of class com.kotlin.thenotepadapplication.viewmodel.MainActivityViewModel
我认为这是因为当我在Fragment中(即在该行中)创建ViewModel类的实例时
mainActivityViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
我实际上并没有传递Context对象的构造函数参数。结果,该应用每次都崩溃。

最佳答案

如果您需要将contextViewModel传递到Repository,请使用AndroidViewModel,这可以占用applicationContext,还需要创建实例。
还要检查android documentation here
因此进行这些更改
ViewModel类:

class MainActivityViewModel(
application: Application
) : AndroidViewModel(application) {
// Access context from application, pass it to Repository
}
存储库类:
class DatabaseRepository(
context: Context
) {
// Pass context to Helper class
NotepadEntryDatabaseHelper(context)
}
现在,您需要使用此类来为 AndroidViewModel创建实例。
工厂类别:
class ActiityViewModelFactory(
private val application: Application
) :
ViewModelProvider.Factory {

@Suppress("unchecked_cast")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(YourViewModelClass::class.java)) {
return YourViewModelClass(application) as T
}
throw IllegalArgumentException("Cannot create instance for class ViewModelClass")
}
}
现在,在您的 Activity 或片段中,您需要将工厂与viewModel一起传递,如下所示:
片段或 Activity 类:
val factory = YourViewModelFactory(application)
val viewModel = ViewModelProvider(this, factory).get(YourViewModelFactory::class.java)
希望这行得通。如果您遇到错误,请进一步告知我。

关于android - 如何在Android中从Fragment传递Context对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63939905/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com