- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我最近学习了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()的开头初始化对象。
java.lang.RuntimeException: Cannot create an instance of class com.kotlin.thenotepadapplication.viewmodel.MainActivityViewModel
我认为这是因为当我在Fragment中(即在该行中)创建ViewModel类的实例时
mainActivityViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
我实际上并没有传递Context对象的构造函数参数。结果,该应用每次都崩溃。
最佳答案
如果您需要将context
从ViewModel
传递到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一起传递,如下所示:
val factory = YourViewModelFactory(application)
val viewModel = ViewModelProvider(this, factory).get(YourViewModelFactory::class.java)
希望这行得通。如果您遇到错误,请进一步告知我。
关于android - 如何在Android中从Fragment传递Context对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63939905/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!