Android - сохранить ArrayList постоянным - PullRequest
0 голосов
/ 18 февраля 2020

Мое приложение отображает список различных категорий (травы, гарниры, ...) в RecyclerView. В зависимости от категории, по которой вы щелкнули, открывается новое действие с новым RecylcerView, содержащее все ингредиенты.

Сейчас у меня есть ArrayList, который заполняется ингредиентами через «.add» в зависимости от выбранной категории.

Проблема, с которой я сейчас сталкиваюсь, заключается в том, что я хочу реализовать опцию, позволяющую пользователю добавлять собственные ингредиенты. Я пытался сохранить ArrayList, содержащий ингредиенты в SharedPreferences, с помощью Gson, но мне не удалось добавить элементы, поскольку он всегда переписывал текущий список.

Как лучше всего хранить ингредиенты? Комната, 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
    }

1 Ответ

0 голосов
/ 18 февраля 2020

Я лично думаю, что Json / Gson в SharedPreference - это самый простой способ go, если элементов так мало. Я бы справился с этим, сохранив список в памяти при запуске приложения и сохранив список обратно в SharedPreference при завершении работы приложения. Кроме того, когда приложение остановлено для хорошей меры, потому что вы не можете на 100% быть уверенным, что будет вызван onDestroy.

Итак, сначала я бы сделал класс для хранения данных. Если бы вы использовали фрагменты, которые все находятся в одном действии, вы бы поместили это в ViewModel. Но так как они являются отдельными видами деятельности, вам нужен синглтон для них. (Google не рекомендует использовать несколько Активностей, потому что трудно обмениваться данными между ними. Но это не невозможно. Это то, что мы делали до Фрагментов.)

Чтобы сделать это как единое целое, у вас может быть класс, подобный this:

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() любого действия, которое изменяет список.

Более правильно, данные в этом классе будут доступны только с неизменяемыми списками, и вы добавите функции для добавления и удаления элементы, поэтому только этот класс напрямую изменяет списки. Я не хотел слишком усложнять пример, но для инкапсуляции было бы лучше, чтобы Activity (которые должны быть чистыми компонентами пользовательского интерфейса) напрямую не модифицировали структуры данных.

...