Android 将数据传递到远程服务器

Android 将数据传递到远程服务器,android,kotlin,retrofit,retrofit2,kotlin-coroutines,Android,Kotlin,Retrofit,Retrofit2,Kotlin Coroutines,通过使用Kotlin、Reformation和Coroutines,我定义了一个从远程服务器获取数据的接口,最重要的是将所选RecyclerView项的id传递回服务器 interface CourseService { @GET("/mobile/feed/course_data.php") suspend fun getCourseData(@Query("pathName") pathName: String): Response<List<Course>

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

interface CourseService {
    @GET("/mobile/feed/course_data.php")
    suspend fun getCourseData(@Query("pathName") pathName: String): Response<List<Course>>
}
我将所选项目的值传递给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)
    }
}
但是,我不能在运行之前给它一个固定值,因为当用户从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

如何解决此问题?

您应该在
视图模型中调用
课程定位
的挂起功能
调用Web服务
。这是您的存储库:

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()
        }
    }
}
class CourseRepository(val应用程序:应用程序){
挂起fun callWebService(路径:path):列表{
返回withContext(Dispatchers.IO){
val reformation=reformation.Builder().baseUrl(WEB_服务_URL).addConverterFactory(MoshiConverterFactory.create()).build()
val service=reformation.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
}
fun getCourseData(路径:path):LiveData{
val response=MutableLiveData()
viewModelScope.launch{
response.postValue(repository.callWebService(path))
}
返回响应
}
然后调用
viewModel。从
活动
片段
或获取有效
路径
值的任何位置获取课程数据(路径)


不要忘记将
实现“androidx.lifecycle:lifecycle viewmodel ktx:2.2.0”
包含在你的gradle文件中。

你应该在
视图模型中调用你的
课程定位
的挂起功能
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()
        }
    }
}
class CourseRepository(val应用程序:应用程序){
挂起fun callWebService(路径:path):列表{
返回withContext(Dispatchers.IO){
val reformation=reformation.Builder().baseUrl(WEB_服务_URL).addConverterFactory(MoshiConverterFactory.create()).build()
val service=reformation.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
}
fun getCourseData(路径:path):LiveData{
val response=MutableLiveData()
viewModelScope.launch{
response.postValue(repository.callWebService(path))
}
返回响应
}
然后调用
viewModel。从
活动
片段
或获取有效
路径
值的任何位置获取课程数据(路径)


别忘了将
实现“androidx.lifecycle:lifecycle viewmodel ktx:2.2.0”
包含到您的gradle文件中。

在几天的时间里,我一直认为我的代码是错误的,事实证明,每次我返回以选择不同的路径时,我的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)
    }
}

经过几天的思考,我的代码是错误的,结果证明我的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)
    }
}

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


因此,您的注意力应该集中在为什么不再提取数据上,这是导致RecyclerView和Fragment保留相同第一视图的原因。

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


因此,您的注意力应该集中在为什么不再提取数据上,这是导致RecyclerView和Fragment保留相同第一视图的原因。

使用selectedItem时会发生什么?错误是什么?@codebrane,没有错误,但根据结果,它看起来像是作为null@codebrane,如果我在代码中的任何地方预定义selectedItem=“WEB001”,则表明在courseFragment中selectedItem为null的操作非常有效。代码似乎没有将其传递给片段,因此callWebService将selectedId设置为Null您可以将带有HttpLoggingInterceptor.Level.BODY的HttpLoggingInterceptor添加到OkHttpClient,以查看调用发送到服务器的内容使用selectedItem时会发生什么?错误是什么?@codebrane,没有错误,但根据结果,它看起来像是作为null@codebrane,如果我在代码中的任何地方预定义selectedItem=“WEB001”,则表明在courseFragment中selectedItem为null的操作非常有效。代码似乎没有将其传递给片段,因此callWebService被选择为null。您可以向OkHttpClient添加一个带有HttpLoggingInterceptor.Level.BODY的HttpLoggingInterceptor,以查看调用发送到服务器的内容,尽管我使用了不同的工作方式,你的代码确实帮助我解决了另一个问题,那就是如何传递路径Id,谢谢你。虽然我使用了不同的工作方式,但你的代码确实帮助我解决了另一个问题,那就是如何传递路径Id,谢谢你。