Android-存储阵列列表持久化



我的应用程序正在RecyclerView中显示各种类别(草药、配菜等(的列表。根据您单击的类别,会打开一个带有新RecylcerView的新"活动",其中包含所有成分。

现在我有一个ArrayList,它通过".add"填充成分,具体取决于所选的类别。

我现在面临的问题是,我想为用户实现一个添加自己的配料的选项。我尝试使用Gson将包含成分的ArrayList存储在SharedPreferences中,但我无法添加元素,因为它总是覆盖当前列表。

储存原料的最佳方式是什么?一个房间,sqlite。。?在没有进一步解释的情况下,配料表最多只包含约70项

提前谢谢。

编辑:

CatList.kt

class CatList : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cat_list)
//Create List for categories
val cats = ArrayList<IngCat>()
//Fill categories
cats.add(IngCat(R.drawable.herbs, "Herbs"))
cats.add(IngCat(R.drawable.fluessiges, "Liquids"))
cats.add(IngCat(R.drawable.festes, "Solids"))
cats.add(IngCat(R.drawable.beilagen, "Sides"))
//Recyclerview
id_rv_CatList.layoutManager = LinearLayoutManager(this)
id_rv_CatList.adapter =
CatListAdapter(cats) {listItem, position -> //go to Ingredient List Activity
goToIngList(position, listItem.name)
}
//id_rv_CatList.addItemDecoration(DividerItemDecoration(this,DividerItemDecoration.HORIZONTAL))
//actionbar
val actionbar = supportActionBar
//set actionbar title
actionbar!!.title = "Ingredient - Categories"
}
private fun goToIngList(cat: Int, name: String){
val intent = Intent(this, IngList::class.java)
intent.putExtra("Category", cat)
intent.putExtra("Name", name)
startActivity(intent)
}
}
data class IngCat(var mImageResource:Int, var name:String)

IngList.kt

class IngList : AppCompatActivity() {
companion object {
var categoryChoosen : Int = 0
var catName : String = "Err"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ing_list)
//Initilize Ingredient List
val ings :ArrayList<IngIng> = ArrayList()
//Get category and category name
categoryChoosen = intent.getIntExtra("Kategorie",0)
catName = intent.getStringExtra("Name")!!
when (categoryChoosen) {
0 -> {
ings.add(IngIng("https://doeel.com/images/thumbnails/1100/900/detailed    /92/Turmeric_Powder___Holud_Gura__.png", "Turmeric Powder"))
}
1 -> ings.add(IngIng("https://www.miraherba.de/4923-large_default/bio-ghee-300-g.jpg", "Ghee"))
2 -> ings.add(IngIng("https://www.organicfacts.net/wp-content/uploads/coriander-1.jpg", "Coriander leaves"))
3 -> ings.add(IngIng("https://gbc-cdn-public-media.azureedge.net/img75602.1426x713.jpg", "Potatoes"))
}

//Actionbar Settings
setSupportActionBar(toolbar)
val actionbar = supportActionBar
actionbar!!.title = "Ingredients- $catName"
actionbar.setDisplayHomeAsUpEnabled(true)
//Recyclerview
id_rv_IngList.layoutManager = GridLayoutManager(this,2)
id_rv_IngList.adapter =
IngListAdapter(ings) {//ClickListener RecyclerView
Toast.makeText(this, "Item clicked: ${it.name}", Toast.LENGTH_SHORT).show()
}

//Actionbar
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.actionbar_ing_list, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.id_menu_action_add -> {
val intent = Intent(this, AddIngredient::class.java)
startActivity(intent)
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
}

IngListAdapter.kt

class IngListAdapter (private val ings: ArrayList<IngIng>, val clickListener: (IngIng)->Unit): RecyclerView.Adapter<RecyclerView.ViewHolder>(){
override fun getItemCount(): Int = ings.size

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val v: View = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_ing_list_item, parent, false)
return IngViewHolder(v)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
var currentItem = ings.get(position)
when (holder) {
is IngViewHolder -> {
holder.tvIngList.text = currentItem.name
// holder.ivIngImage.setImageResource(currentItem.mImageResource)
Picasso.get().load(currentItem.mImageResource).placeholder(R.drawable.ic_broken_image_black_200dp).error(R.drawable.ic_broken_image_red_24dp).into(holder.ivIngImage)
holder.cvIngCard.setOnClickListener{
clickListener(currentItem)
}
}
}
}
}
class IngViewHolder (view: View) : RecyclerView.ViewHolder(view) {
val tvIngList: TextView = view.id_text_ing
val ivIngImage: ImageView = view.id_img_ing
val cvIngCard: MaterialCardView = view.id_cv_ing_list
}

我个人认为,如果项目太少,那么SharedPreference中的Json/Gson是最简单的方法。我处理它的方法是在应用程序启动时将列表存储在内存中,并在应用程序关闭时将列表持久化回SharedPreference。此外,当应用程序因无法100%确定会调用onDestroy而被停止时。

因此,首先我会创建一个类来存储数据。如果您使用的片段都在同一个"活动"中,那么您应该将其放入ViewModel中。但是,由于它们是独立的活动,您需要为它们提供一个singleton。(谷歌不建议使用多个活动,因为很难在它们之间共享数据。但这并非不可能。这是我们在碎片之前所做的。(

要将其作为一个单例来实现,您可以有一个这样的类:

class IngredientsRepo private constructor (application: Application) {
companion object {
private val INSTANCE: IngredientsRepo? = null
fun getInstance(application: Application) = 
INSTANCE ?: IngredientsRepo(application).also { INSTANCE = it }
private const KEY_JSON_PREF = "ingredientsJson"
}
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(application)
val herbsList: MutableList<IngCat>
val liquidsList: MutableList<IngCat>
val solidsList: MutableList<IngCat>
val sidesList: MutableList<IngCat>
init {
val json = sharedPreferences.getString(KEY_JSON_PREF, null)
if (json == null) {
// initialize your list contents for the first time
} else {
// convert your json and fill the data into your lists
}
}
fun save {
val jsonString = // Convert your lists to Json
sharedPreferences.edit().putString(KEY_JSON_PREF, jsonString).apply()
}
}

该类负责设置您的列表。您可以使用IngredientsRepo.getInstance(this)从任何"活动"中检索它,也可以随时从列表中添加和删除项目。您也可以随时在它上调用save来持久化最新的数据。在修改列表的任何"活动"的onStop()中执行此操作可能就足够了。

更恰当地说,这个类中的数据将只使用不可变列表公开,并且您将添加用于添加和删除项的函数,因此只有这个类直接修改列表。我不想使示例过于复杂,但封装最好不要让Activities(应该是纯UI组件(直接修改数据结构。

最新更新