我开始学习Android(kotlin、mvvm、coroutine)。我正在尝试调用(GET)这个由The Movie DB提供的API。
http:// api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=#################
我只收到响应错误,不知道发生了什么,因为我在日志中没有看到请求和响应。因此,添加一个日志记录来改造客户端。
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
class MovieListFragment : Fragment() {
private val viewModel: MovieListViewModel by viewModels {
val logging = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }
val httpClient = OkHttpClient.Builder().addInterceptor(logging).build()
val moshi = Moshi.Builder().build()
val movieService = Retrofit.Builder()
.baseUrl("http://api.themoviedb.org/3")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.client(httpClient)
.build()
.create(MovieService::class.java)
val repository = MovieRepository(movieService)
MovieListViewModelFactory(repository)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_movie_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView: RecyclerView = view.findViewById(R.id.recycler_view)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
val adapter = MovieListAdapter(requireContext())
recyclerView.adapter = adapter
Log.d("MovieListFragment", "Test log to check if logging works")
viewModel.movies.observe(viewLifecycleOwner, Observer { movies ->
adapter.submitList(movies)
})
viewModel.error.observe(viewLifecycleOwner, Observer { error ->
print(error)
})
if (NetworkUtils.isNetworkAvailable(requireContext())) {
viewModel.fetchPopularMovies()
} else {
print("No internet..")
}
}
}
interface MovieService {
@GET("/discover/movie")
suspend fun getPopularMovies(
@Query("api_key") apiKey: String,
@Query("sort_by") sortBy: String
): MovieResponse
}
class MovieRepository(private val movieService: MovieService) {
suspend fun getPopularMovies(): MovieResponse {
return movieService.getPopularMovies("##################", "popularity.desc")
}
}
还要设置一些网络安全设置,因为端点不是 https。
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">api.themoviedb.org</domain>
</domain-config>
</network-security-config>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:networkSecurityConfig="@xml/network_security_config"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MvvMTest"
tools:targetApi="31">
<activity android:name=".ui.main.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Logcat 在 Android Studio 中运行良好。问题一定出在我的代码中。有什么想法吗?
将互联网权限添加到清单中:
<uses-permission android:name="android.permission.INTERNET" />