使用viewpager创建多个片段



当这个特定的片段被打开时,列表第二项的数据(问题模型)被膨胀到ui,并且生命周期方法也被调用两次。

我也放了一个滑动刷新检查。刷新后对应的数据来了

如果我滑动到第3或第4个位置,然后返回到第一页,那么正确的数据也被夸大了。

分页适配器类

import android.util.Log
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.iisc.englishgyani.fragments.*
import com.iisc.englishgyani.models.topic_details.PracticeModel
class TopicPracticeAdapter(var fragmentManager: FragmentManager, var practiceList: ArrayList<PracticeModel>, var topic_name: String, var topicId: Int): FragmentPagerAdapter(fragmentManager) {
private val TAG = TopicPracticeAdapter::class.java.simpleName
init {
Log.d(TAG, "TopicPracticeAdapter: $practiceList")
Log.d(TAG, "topic_name: $topic_name")
}
override fun getCount() = practiceList.size
override fun getItem(position: Int): Fragment {
return when {
practiceList.get(position).type.equals("text") -> {
FragmentTutorialText.newInstance(practiceList.get(position).tutorialModel, topic_name)
}
practiceList.get(position).type.equals("video") -> {
FragmentTutorialVideo.newInstance(practiceList.get(position).tutorialModel, topic_name)
}
practiceList.get(position).type.equals("link") -> {
FragmentTutorialDoc.newInstance(practiceList.get(position).tutorialModel, topic_name)
}
practiceList.get(position).type.equals("MCQ") -> {
FragmentMCQ.newInstance(practiceList.get(position).questionModel, topicId)
}
practiceList.get(position).type.equals("FIB") -> {
FragmentMCQ.newInstance(practiceList.get(position).questionModel, topicId)
}
practiceList.get(position).type.equals("DND") -> {
return FragmentDragAndDrop().newInstance(practiceList.get(position).questionModel, topicId)
}
practiceList.get(position).type.equals("MTF") -> {
FragmentMatchTheFollowing.newInstance(practiceList.get(position).questionModel, topicId)
}
else -> {
FragmentTutorialText.newInstance(practiceList.get(position).tutorialModel, topic_name)
}
}
}
}

FragmentDragAndDrop


import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import com.google.android.flexbox.*
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.iisc.englishgyani.adapters.SentenceAdapter
import com.iisc.englishgyani.adapters.WordsAdapter
import com.iisc.englishgyani.callbacks.DropListener
import com.iisc.englishgyani.databinding.FragmentDragAndDropBinding
import com.iisc.englishgyani.interfaces.NextFragment
import com.iisc.englishgyani.models.answer.AnswerResponse
import com.iisc.englishgyani.models.topic_details.QuestionModel
import com.iisc.englishgyani.network.ApiService
import com.iisc.englishgyani.network.ApiUtils
import com.iisc.englishgyani.utils.Constants.Companion.showNextFragment
import com.iisc.englishgyani.utils.NetworkHelper
import com.iisc.englishgyani.utils.ProgressDialogHelper
import okhttp3.MediaType
import okhttp3.RequestBody
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_QUESTION_MODEL = "questionModel"
private const val ARG_TOPIC_ID = "topicId"
private val words = ArrayList<String>()
private val sentence = mutableListOf<String>()
class FragmentDragAndDrop : Fragment() {
private lateinit var nextFragment: NextFragment
private var _binding: FragmentDragAndDropBinding? = null
private val binding get() = _binding!!
private var selectedWord = ""
private val TAG = FragmentDragAndDrop::class.java.simpleName
// TODO: Rename and change types of parameters
private var questionModel: QuestionModel? = null
private var topicId: Int? = null
private var mAPIService: ApiService? = null
var loader: ProgressDialogHelper? = null
override fun onAttach(context: Context) {
super.onAttach(context)
try {
nextFragment = context as NextFragment
} catch (e: ClassCastException) {
throw ClassCastException((context as Activity).localClassName
+ " must implement OnButtonClickListener")
}
Log.d(TAG, "onAttach: ")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate: ")
mAPIService = ApiUtils.getApiService()
loader = context?.let {
ProgressDialogHelper(it)
}
}
private fun setUI(){
Log.d(TAG, "setUI showNextFragment: $showNextFragment")
//        if(showNextFragment) {
//
//            showNextFragment = false
activity?.actionBar?.title = questionModel?.qid.toString()
Log.d(TAG, "setUI backStackEntryCount: ${activity?.supportFragmentManager?.backStackEntryCount}")
binding.fragmentSwipe.isRefreshing = false
arguments?.let {
questionModel = it.getParcelable(ARG_QUESTION_MODEL)
topicId = it.getInt(ARG_TOPIC_ID)
}
Log.d(TAG, "setUI: $questionModel")
Log.d(TAG, "setUI: $topicId")
Log.d(TAG, "setUI qid: ${questionModel?.qid}")
binding.fragmentSwipe.setOnRefreshListener {
setUI()
}
words.clear()
questionModel?.choices?.forEach {
words.add(it)
}
val sentenceAdapter = SentenceAdapter {
selectedWord = it
}.apply {
submitList(sentence)
}
val wordsAdapter = WordsAdapter {
selectedWord = it
}.apply {
submitList(words)
}
val layoutManager = FlexboxLayoutManager(context, FlexDirection.ROW, FlexWrap.WRAP).apply {
justifyContent = JustifyContent.FLEX_START
alignItems = AlignItems.FLEX_START
}
//        layoutManager.orientation = GridLayoutManager.VERTICAL
binding.tvInst.text = questionModel?.desc
binding.tvQues.text = questionModel?.question?.get(0)?.question
binding.rvSentence.layoutManager = layoutManager
binding.rvSentence.adapter = sentenceAdapter
binding.rvSentence.setOnDragListener(
DropListener {
Log.d(TAG, "setUI selectedWord: $selectedWord")
Log.d(TAG, "setUI sentenceAdapter: ${sentenceAdapter.currentList}")
Log.d(TAG, "setUI wordsAdapter: ${wordsAdapter.currentList}")
wordsAdapter.removeItem(selectedWord)
if (!sentence.contains(selectedWord)) {
sentenceAdapter.addItem(selectedWord)
}
//                    sentenceAdapter.notifyDataSetChanged()
//                    wordsAdapter.notifyItemRemoved(words.indexOf(selectedWord))
}
)
binding.rvWords.layoutManager = FlexboxLayoutManager(context, FlexDirection.ROW, FlexWrap.WRAP).apply {
justifyContent = JustifyContent.FLEX_START
alignItems = AlignItems.FLEX_START
}
binding.rvWords.adapter = wordsAdapter
binding.rvWords.setOnDragListener(
DropListener {
sentenceAdapter.removeItem(selectedWord)
wordsAdapter.addItem(selectedWord)
}
)
binding.cardSubmit.setOnClickListener {
val selectedAnswer = StringBuffer()
sentenceAdapter.currentList.forEach {
//                selectedAnswer.commonPrefixWith(" ", sentenceAdapter.currentList.indexOf(it) == sentenceAdapter.currentList.size)
selectedAnswer.append("$it ")
}
Log.d(TAG, "setUI:${selectedAnswer.lastIndex}")
Log.d(TAG, "setUI:${selectedAnswer.length}")
Log.d(TAG, "setUI:${selectedAnswer.substring(0, selectedAnswer.lastIndex)}")
val choice = ArrayList<String>()
choice.add(selectedAnswer.substring(0, selectedAnswer.lastIndex))
validate(choice)
}
//        }
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
Log.d(TAG, "onCreateView: ")
_binding = FragmentDragAndDropBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUI()
Log.d(TAG, "onViewCreated: ")
Log.d(TAG, "onViewCreated questionModel: $questionModel")
Log.d(TAG, "onViewCreated topicId: $topicId")
}
private fun validate(choice: ArrayList<String>?) {
// req -> {topic_id, qid, type, category, email_id, question array -> {question, user_answer}}
// res <- {question array, type}
try {
if (NetworkHelper.isNetworkAvailable(context!!)) {
submitAnswer(choice)
} else {
Toast.makeText(context, "Connect to internet", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun submitAnswer(choice: ArrayList<String>?) {
loader?.showProgressDialog()
val jsonObject = JSONObject()
val question = JSONArray()
//        question.put(questionModel?.question?.get(0)?.question?.let {
//            choice?.let { choice ->
//                QAPairModel(it, choice.get(0))
//            }
//        })
val jsonObjectQuestion = JSONObject()
jsonObjectQuestion.put("question", questionModel?.question?.get(0)?.question)
jsonObjectQuestion.put("user_answer", choice?.get(0))
question.put(jsonObjectQuestion)
try {
val account = GoogleSignIn.getLastSignedInAccount(context)
account?.let {
jsonObject.put("topic_id", topicId)
jsonObject.put("type", questionModel?.type)
jsonObject.put("qid", questionModel?.qid)
jsonObject.put("email_id", account.email)
jsonObject.put("category", "grammer")
jsonObject.put("question", question)
}
} catch (e: JSONException) {
e.printStackTrace()
}
Log.d(TAG, "submitAnswer: json object $jsonObject")
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.toString())
Log.d(TAG, "onResponse RequestBody: $body")
mAPIService = ApiUtils.getApiService()
mAPIService?.answer(body)?.enqueue(object : Callback<AnswerResponse> {
override fun onResponse(call: Call<AnswerResponse>, response: Response<AnswerResponse>) {
Log.d(TAG, "onResponse: ${response.body()}")
if (response.isSuccessful) {
loader?.hideProgressDialog()
try {
Toast.makeText(context, response.body()?.message, Toast.LENGTH_SHORT).show()
nextFragment.showNextFragment()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
override fun onFailure(call: Call<AnswerResponse>, t: Throwable) {
loader?.hideProgressDialog()
Log.d(TAG, "onFailure: ${t.message}")
}
})
}
//    companion object {
//        /**
//         * Use this factory method to create a new instance of
//         * this fragment using the provided parameters.
//         *
//         * @param questionModel Parameter 1.
//         * @param topicId Parameter 2.
//         * @return A new instance of fragment FragmentDragAndDrop.
//         */
//        // TODO: Rename and change types and number of parameters
//        @JvmStatic
//        fun newInstance(questionModel: QuestionModel?, topicId: Int) =
//                FragmentDragAndDrop().apply {
//                    arguments = Bundle().apply {
//                        putParcelable(ARG_QUESTION_MODEL, questionModel)
//                        putInt(ARG_TOPIC_ID, topicId)
//                    }
//                }
//    }

fun newInstance(questionModel: QuestionModel?, topicId: Int) =
FragmentDragAndDrop().apply {
arguments = Bundle().apply {
putParcelable(ARG_QUESTION_MODEL, questionModel)
putInt(ARG_TOPIC_ID, topicId)
}
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause: ")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy: ")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume: ")
setUI()
}
override fun onDestroyView() {
super.onDestroyView()
Log.d(TAG, "onDestroyView: ")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop: ")
}
}

默认情况下,片段的左侧和右侧被预加载到ViewPager中。它不允许设置小于1的"屏幕外页面限制"。但在Viewpager 2中,你可以将最小的屏幕外页面限制设置为零。所以只有当前片段会被加载。

  • viewPager2.setOffscreenPageLimit (0);

最新更新