【问题标题】:Passing data to a remote server将数据传递到远程服务器
【发布时间】:2020-08-15 18:28:58
【问题描述】:

使用 Kotlin、Retrofit 和 Coroutines,我定义了一个接口来从远程服务器获取数据,最重要的是,将选定的 RecyclerView 项目的 id 传递回服务器。

interface CourseService {
    @GET("/mobile/feed/course_data.php")
    suspend fun getCourseData(@Query("pathName") pathName: String): Response<List<Course>>
}

在这里,我从 MainFragment 的 RecyclerView 中获取所选项目的 id,并将其存储在“selectedItem”变量中。

override fun onPathItemClick(path: Path) {
    viewModel.selectedItem.value = path
    selectedItem= viewModel.selectedItem.value!!.path_id
    navController.navigate(R.id.action_mainFragment_to_courseFragment)
}

我将所选项目的值传递给 getCourseData() 函数

class CourseRepository(val app: Application) {

    val courseData = MutableLiveData<List<Course>>()

    init {
        CoroutineScope(Dispatchers.IO).launch {
            callWebService()
        }
    }

    @WorkerThread
    suspend fun callWebService() {
            val retrofit = Retrofit.Builder().baseUrl(WEB_SERVICE_URL).addConverterFactory(MoshiConverterFactory.create()).build()
            val service = retrofit.create(CourseService::class.java)
            val serviceData = service.getCourseData(selectedItem).body() ?: emptyList()
            courseData.postValue(serviceData)
    }
}

但我没有得到任何结果,似乎传递给 getCourseData() 函数的值为 null,但在检查日志时确实有一个值。

所以如果我在我的代码中的任何地方给它一个预定义的值,如下所示,一切都很好

    selectedItem= "MOB001"
    val serviceData = service.getCourseData(selectedItem).body() ?: emptyList()

但是,我不能在运行前给它一个固定值,因为当用户从 RecyclerView 中选择一个项目时会检索该值。

这些是我的多个日志:

2020-05-01 13:56:30.431 23843-23843/ I/mylog: Main Fragment before item click: selectedItem = 
2020-05-01 13:56:37.757 23843-23843/ I/mylog: Main Fragment after item click: selectedItem = WEB001
2020-05-01 13:56:37.763 23843-23843/ I/mylog: Course Fragment onCreateView(): selectedItem = WEB001
2020-05-01 13:56:37.772 23843-23901/ I/mylog: Course Fragment CourseRepository: selectedItem = WEB001

我该如何克服这个问题?

【问题讨论】:

  • 使用 selectedItem 时会发生什么?错误是什么?
  • @codebrane,没有错误,但是根据结果,好像是作为null传递的
  • @codebrane,如果我在代码中的任何位置预定义 selectedItem = "WEB001",它工作正常
  • 表示在 courseFragment 中 selectedItem 为空。代码似乎没有将其传递给片段,因此 callWebService 将 selectedId 设为 null
  • 您可以将带有 HttpLoggingInterceptor.Level.BODY 的 HttpLoggingInterceptor 添加到 OkHttpClient 以查看调用发送到服务器的内容

标签: android kotlin retrofit retrofit2 kotlin-coroutines


【解决方案1】:

您应该在您的ViewModel 中调用您的CourseRepository 的挂起函数callWebService。这是您的存储库:

class CourseRepository(val app: Application) {
    suspend fun callWebService(path: Path): List<Course> {
        return withContext(Dispatchers.IO) {
            val retrofit = Retrofit.Builder().baseUrl(WEB_SERVICE_URL).addConverterFactory(MoshiConverterFactory.create()).build()
            val service = retrofit.create(CourseService::class.java)
            service.getCourseData(path.path_id).body() ?: emptyList()
        }
    }
}

然后您应该在 ViewModel 中调用您的存储库函数,如下所示:

fun getCourseData(path: Path): LiveData<List<Course>> {
    val response = MutableLiveData<List<Course>>()
    viewModelScope.launch {
        response.postValue(repository.callWebService(path))
    }
    return response
}

然后,当您获得有效的Path 值时,从您的ActivityFragment 或任何地方调用viewModel. getCourseData(path)

不要忘记将implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" 包含到您的 gradle 文件中。

【讨论】:

  • 虽然我使用了不同的工作方式,但你的代码确实帮助我解决了另一个问题,即如何传递路径 ID,所以谢谢你。
【解决方案2】:

您的代码似乎是正确的,但是,您的 RecyclerView 很有可能第一次被填充,并且每次您返回并选择另一个使用相同数据和视图填充的路径时。

因此,你的注意力应该集中在为什么没有再次获取数据,这就是 RecyclerView 和 Fragment 保持相同的第一个视图的原因。

【讨论】:

    【解决方案3】:

    经过几天的思考我的代码是错误的,结果发现我的 RecyclerView 适配器每次我回到选择不同的路径时都加载相同的视图,因为我的 RecyclerView 在只调用一次的 onCreateView() 函数中被夸大了仅当片段第一次膨胀时。

    class CourseFragment : Fragment(),
        CourseRecyclerAdapter.CourseItemListener {
    
        private lateinit var viewModel: CourseViewModel
        private lateinit var recyclerView: RecyclerView
        private lateinit var navController: NavController
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
    
            val view = inflater.inflate(R.layout.fragment_course, container, false)
            recyclerView = view.findViewById(R.id.courseRecyclerView)
            navController = Navigation.findNavController(requireActivity(), R.id.nav_host )
            viewModel = ViewModelProvider(requireActivity()).get(CourseViewModel::class.java)
            viewModel.courseData.observe(viewLifecycleOwner, Observer {
                val adapter =
                    CourseRecyclerAdapter(
                        requireContext(),
                        it,
                        this
                    )
                recyclerView.adapter = adapter
            } )
            return view
        }
    
        override fun onCourseItemClick(course: Course) {
            viewModel.selectedCourse.value = course
            navController.navigate(R.id.action_courseFragment_to_detailFragment)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 2014-07-22
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 2013-09-13
      • 2010-11-23
      相关资源
      最近更新 更多