I am requesting for a xml data, but the response was not correct. The response was jumbled.
Here are some of my code:
NetworkUtils:
object NetworkUtils {
private val client = OkHttpClient.Builder()
.cookieJar(object : CookieJar{
override fun loadForRequest(url: HttpUrl): List<Cookie> {
return CookiesManager.getCookies()
}
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
CookiesManager.saveCookies(cookies)
}
})
.build()
fun getUrl(url: String, callback: Callback) {
val request = Request.Builder()
.url(url)
.get()
.build()
client.newCall(request).enqueue(callback)
}
...
}
VideoManager:
object VideoManager {
...
fun getDanmaku(cid : Long, callback: Callback){
NetworkUtils.getUrl("http://api.bilibili.com/x/v1/dm/list.so?oid=$cid", callback)
}
...
}
VideoPlayingFragment:
#SuppressLint("ResourceType")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val danmakuContext : DanmakuContext = DanmakuContext.create()
val maxLinesPair = HashMap<Int, Int>()
maxLinesPair[BaseDanmaku.TYPE_SCROLL_RL] = 5
maxLinesPair[BaseDanmaku.TYPE_SCROLL_LR] = 5
val overlappingEnablePair = HashMap<Int, Boolean>()
overlappingEnablePair[BaseDanmaku.TYPE_SCROLL_LR] = true
overlappingEnablePair[BaseDanmaku.TYPE_SCROLL_RL] = true
overlappingEnablePair[BaseDanmaku.TYPE_FIX_BOTTOM] = true
danmakuContext.setDanmakuStyle(IDisplayer.DANMAKU_STYLE_STROKEN, 3F) //设置描边样式
.setDuplicateMergingEnabled(false)
.setScrollSpeedFactor(1.2f) //是否启用合并重复弹幕
.setScaleTextSize(1.5f) //设置弹幕滚动速度系数,只对滚动弹幕有效
.setCacheStuffer(SpannedCacheStuffer()) // 图文混排使用SpannedCacheStuffer 设置缓存绘制填充器,默认使用{#link SimpleTextCacheStuffer}只支持纯文字显示, 如果需要图文混排请设置{#link SpannedCacheStuffer}如果需要定制其他样式请扩展{#link SimpleTextCacheStuffer}|{#link SpannedCacheStuffer}
.setMaximumLines(maxLinesPair) //设置最大显示行数
.preventOverlapping(overlappingEnablePair) //设置防弹幕重叠,null为允许重叠
val loader : ILoader = DanmakuLoaderFactory.create(DanmakuLoaderFactory.TAG_BILI)
VideoManager.getDanmaku((activity as VideoActivity).currentVideo.cid, object : Callback{
override fun onFailure(call: Call, e: IOException) {
mThreadPool.execute{
requireActivity().runOnUiThread{
Toast.makeText(requireContext(), "加载弹幕失败!", Toast.LENGTH_SHORT).show()
}
}
}
override fun onResponse(call: Call, response: Response) {
try{
val responseIs = response.body?.byteStream()
val str = String(responseIs?.readBytes()!!, Charsets.UTF_8)
Log.d(Application.getTag(), "onResponse: $str")
loader.load(str)
}
catch (e : IllegalDataException){
e.printStackTrace()
mThreadPool.execute{
requireActivity().runOnUiThread{
Toast.makeText(requireContext(), "加载弹幕失败!", Toast.LENGTH_SHORT).show()
}
}
}
val danmukuParser = BiliDanmukuParser()
val dataSource : IDataSource<*> = loader.dataSource
danmukuParser.load(dataSource)
binding.danmakuView.setCallback(object : DrawHandler.Callback{
override fun prepared() {
Log.d(Application.getTag(), "prepared: ")
VideoManager.getVideoUrl((activity as VideoActivity).currentVideo.bvid, (activity as VideoActivity).currentVideo.cid, object : Callback{
override fun onFailure(call: Call, e: IOException) {
mThreadPool.execute{
requireActivity().runOnUiThread{
Toast.makeText(requireContext(), "加载视频失败!", Toast.LENGTH_SHORT).show()
}
}
}
override fun onResponse(call: Call, response: Response) {
val responseString = response.body?.string()
mThreadPool.execute{
val videoUrls : VideoStreams = Gson().fromJson(responseString, VideoStreams::class.java)
requireActivity().runOnUiThread{
val uri : Uri = Uri.parse(videoUrls.data.durl[0].url)
val headers = HashMap<String, String>()
headers["User-Agent"] = "Mozilla/5.0 BiliDroid/*.*.* (bbcallen#gmail.com)"
headers["Referer"] = "https://bilibili.com/"
binding.videoView.setVideoURI(uri, headers)
binding.videoView.start()
val mediaController = MediaController(requireContext())
binding.videoView.setMediaController(mediaController)
//binding.danmakuView.
binding.danmakuView.start()
}
}
}
})
}
override fun updateTimer(timer: DanmakuTimer?) {
Log.d(Application.getTag(), "updateTimer: ")
}
override fun drawingFinished() {
Log.d(Application.getTag(), "drawingFinished: ")
}
})
binding.danmakuView.prepare(danmukuParser, danmakuContext)
binding.danmakuView.enableDanmakuDrawingCache(true) //true在模拟器上运行有问题
}
})
}
And here is one of my requested datas:
I've been searching on the internet but none of the method worked. Such as removing Accept-Encoding header. Can someone help me fix this? Thanks in advance.
Related
I was trying to get response from viewModel But, I am having hard time to use the response data on another activity to display it on a text view.
I have already setup the backend for the repo's and interfaces, data classes etc...
Thank you!!!
// View Model
class HomeActivityViewModel : ViewModel() {
lateinit var createPostLiveData: MutableLiveData<PostResponseData?>
init {
createPostLiveData = MutableLiveData()
}
fun getPostLiveObserver(): MutableLiveData<PostResponseData?> {
return createPostLiveData
}
fun createPostData(postdata: PostData) {
val retroService = RetrofitApiFactory.retroInstance().create(ChefApi::class.java)
val call = retroService.postData(postdata)
call.enqueue(object : Callback<PostResponseData> {
override fun onResponse(
call: Call<PostResponseData>,
response: Response<PostResponseData>
) {
if (response.isSuccessful) {
createPostLiveData.postValue(response.body())
var text = response.body()!!.choices[0].text
Log.d("response", text) // only shows the one in the viewModel
} else {
createPostLiveData.postValue(null)
Log.d("failed", response.errorBody().toString())
}
}
override fun onFailure(call: Call<PostResponseData>, t: Throwable) {
Log.d("failed", t.message.toString())
createPostLiveData.postValue(null)
}
})
}
}
Activity.kt
class HomeActivity : AppCompatActivity() {
lateinit var mAuth: FirebaseAuth
lateinit var viewModel: HomeActivityViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home_actvity)
mAuth = FirebaseAuth.getInstance()
initViewModel()
generate.setOnClickListener {
createPost()
}
logout.setOnClickListener {
logoutUser()
}
}
private fun createPost() {
// creating a post
val prompt = "Some string..."
val postdata = PostData(120, prompt, 0.3, 1.0, 0.0)
viewModel.createPostData(postdata)
}
private fun initViewModel() {
// initialize view model
viewModel = ViewModelProvider(this).get(HomeActivityViewModel::class.java)
viewModel.getPostLiveObserver().observe(this, Observer<PostResponseData?> {
if (it == null) {
Toast.makeText(this#HomeActivity, "Failed to post data", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this#HomeActivity, "Successfully posted data", Toast.LENGTH_SHORT)
.show()
}
})
}
private fun logoutUser() {
mAuth.signOut()
updateUI()
}
private fun updateUI() {
val intent = Intent(this#HomeActivity, MainActivity::class.java)
startActivity(intent)
finish()
}
Try to change your HomeActivityViewModel class and add a LiveData object to it:
class HomeActivityViewModel : ViewModel() {
var _createPostLiveData: MutableLiveData<PostResponseData?>()
// Live data instance
val createPostLiveData
get() = _createPostLiveData
fun createPostData(postdata: PostData) {
val retroService = RetrofitApiFactory.retroInstance().create(ChefApi::class.java)
val call = retroService.postData(postdata)
call.enqueue(object : Callback<PostResponseData> {
override fun onResponse(
call: Call<PostResponseData>,
response: Response<PostResponseData>
) {
if (response.isSuccessful) {
// Update live data value
_createPostLiveData.value = response.body()
var text = response.body()!!.choices[0].text
Log.d("response", text) // only shows the one in the viewModel
} else {
// Update live data value
_createPostLiveData.value = null
Log.d("failed", response.errorBody().toString())
}
}
override fun onFailure(call: Call<PostResponseData>, t: Throwable) {
Log.d("failed", t.message.toString())
// Update live data value
_createPostLiveData.value = null
}
})
}
}
You should then be able to observe the LiveData instance in your Activity:
class HomeActivity : AppCompatActivity() {
lateinit var mAuth: FirebaseAuth
// Initialize view model in declaration
private val viewModel: HomeActivityViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home_actvity)
mAuth = FirebaseAuth.getInstance()
// Observe for `createPostLiveData` changes
viewModel.createPostLiveData.observe(this) {
if (it == null) {
Toast.makeText(this#HomeActivity, "Failed to post data", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this#HomeActivity, "Successfully posted data", Toast.LENGTH_SHORT)
.show()
}
}
generate.setOnClickListener {
createPost()
}
logout.setOnClickListener {
logoutUser()
}
}
private fun createPost() {
// creating a post
val prompt = "Some string..."
val postdata = PostData(120, prompt, 0.3, 1.0, 0.0)
viewModel.createPostData(postdata)
}
...
Ii trying to run the recyclerview, but list item didn't show, and error message is No adapter attached; skipping layout
There is no error with the code, but when try to run, recyclerview doesn't show. Here the main activity, I try to show recyclerview using Parsing Json
companion object {
private val TAG = MainActivity::class.java.simpleName
}
private lateinit var binding: ActivityMainBinding
// private lateinit var adapter: UserAdapter
private var listUser = ArrayList<DataUser>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar?.title = "Github User Search"
binding.rvUser.setHasFixedSize(true)
val layoutManager = LinearLayoutManager(this)
val itemDecoration = DividerItemDecoration(this, layoutManager.orientation)
binding.rvUser.addItemDecoration(itemDecoration)
searchUsername()
getDataUser()
}
fun searchUsername () {
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
val searchView = binding.searchView
searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName))
searchView.queryHint = resources.getString(R.string.search_hint)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String): Boolean {
if(query.isEmpty()){
return true
} else{
listUser.clear()
getSearchUsername(query)
}
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
return false
}
})
}
private fun getSearchUsername(username: String) {
binding.progressBar.visibility = View.VISIBLE
val client = AsyncHttpClient()
client.addHeader("Authorization", "token<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>")
client.addHeader("User-Agent", "request")
client.get(
"https://api.github.com/search/users?q=$username",
object : AsyncHttpResponseHandler() {
override fun onSuccess(
statusCode: Int,
headers: Array<out Header>,
responseBody: ByteArray
) {
binding.progressBar.visibility = View.VISIBLE
val result = String(responseBody)
Log.d(TAG, result)
try {
val jsonArray = JSONArray(result)
for (i in 0 until jsonArray.length()) {
val responseObject = jsonArray.getJSONObject(i)
val userName = responseObject.getString("login")
val id = responseObject.getString("id")
val avatar = responseObject.getString("avatar_url")
listUser.add(DataUser(
userName,
id.toInt(),
avatar
))
}
val adapter = UserAdapter(listUser)
binding.rvUser.adapter = adapter
} catch (e: Exception) {
Log.d(TAG, e.message.toString())
}
}
override fun onFailure(
statusCode: Int,
headers: Array<out Header>,
responseBody: ByteArray,
error: Throwable
) {
binding.progressBar.visibility = View.INVISIBLE
val errorMessage = when (statusCode) {
401 -> "$statusCode : Bad Request"
403 -> "$statusCode : Forbidden"
404 -> "$statusCode : Not Found"
else -> "$statusCode : ${error.message}"
}
Toast.makeText(
this#MainActivity, errorMessage, Toast
.LENGTH_SHORT
).show()
}
})
}
private fun getDataUser() {
binding.progressBar.visibility = View.VISIBLE
val client = AsyncHttpClient()
client.addHeader("Authorization", "token YOUR_GITHUB_API_TOKEN")
client.addHeader("User-Agent", "request")
val url = "https://api.github.com/users"
client.get(url, object : AsyncHttpResponseHandler() {
override fun onSuccess(statusCode: Int, headers: Array<out Header>?, responseBody: ByteArray?) {
binding.progressBar.visibility = View.INVISIBLE
val result = String(responseBody!!)
Log.d(TAG, result)
try {
val jsonArray = JSONArray(result)
for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i)
val username: String = jsonObject.getString("login")
getSearchUsername(username)
}
} catch (e: Exception) {
Toast.makeText(this#MainActivity, e.message, Toast.LENGTH_SHORT)
.show()
e.printStackTrace()
}
}
override fun onFailure(statusCode: Int, headers: Array<out Header>?, responseBody: ByteArray?, error: Throwable?) {
binding.progressBar.visibility = View.INVISIBLE
val errorMessage = when (statusCode) {
401 -> "$statusCode : Bad Request"
403 -> "$statusCode : Forbidden"
404 -> "$statusCode : Not Found"
else -> "$statusCode : ${error?.message + " GIT"}"
}
Toast.makeText(this#MainActivity, errorMessage, Toast.LENGTH_LONG)
.show()
}
})
}
}
And here the adapter
class UserAdapter(private val listDataDetailUser: ArrayList<DataUser>) :
RecyclerView.Adapter<UserAdapter.ListViewHolder>() {
private lateinit var onItemClickCallback: OnItemClickCallback
fun setOnItemCLickCallback(onItemClickCallback: OnItemClickCallback) {
this.onItemClickCallback = onItemClickCallback
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ListViewHolder {
val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.item_profile_list, viewGroup, false)
return ListViewHolder(view)
}
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
val data = listDataDetailUser[position]
Glide.with(holder.itemView.context)
.load(data.avatar_url)
.into(holder.avatar)
holder.username.text = data.login
}
override fun getItemCount(): Int = listDataDetailUser.size
inner class ListViewHolder(view : View) : RecyclerView.ViewHolder(view) {
val avatar: CircleImageView = view.findViewById(R.id.img_profile)
val username: TextView = view.findViewById(R.id.tv_username)
}
interface OnItemClickCallback {
fun onItemClicked(data: DataUser)
}
}
What can I try to resolve this?
You have not added LayoutManager to your Recyclerview.
Try adding LinearLayoutManager which you have created for your ItemDecoration.
binding.rvUser.setLayoutManager(layoutManager);
I have an android application that requests a list from the network and should display it in a recycler view but this does not happen. There are no errors in the logcat. I think the problem is in my function in ViewModel. Help me to understand
My CategoryClient class:
class CategoryClient {
companion object {
const val KEY = "5de979d34658275ac9dc2375"
}
var category: List<Category>? = null
fun loadCategory(): List<Category>? {
// x-apikey interceptor for restdb API
fun createOkHttpClient(): OkHttpClient? {
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor(object : Interceptor {
#Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
val original = chain.request()
val originalHttpUrl = original.url
val url = originalHttpUrl.newBuilder()
.addQueryParameter("apikey", KEY)
.build()
val requestBuilder = original.newBuilder()
.url(url)
val request = requestBuilder.build()
return chain.proceed(request)
}
})
// logging interceptor
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
httpClient.addInterceptor(logging)
return httpClient.build()
}
val retrofit = Retrofit.Builder()
.baseUrl("https://testcategory-d6d7.restdb.io/rest/")
.addConverterFactory(GsonConverterFactory.create())
.client(createOkHttpClient())
.build()
val api = retrofit.create(CategoryApi::class.java)
api.fetchAllCategory().enqueue(object : Callback<List<Category>> {
override fun onFailure(call: Call<List<Category>>, t: Throwable) {
}
override fun onResponse(call: Call<List<Category>>, response: Response<List<Category>>) {
//Log.d(TAG, "onResponse: ${response.body()!![0].name}")
category = response.body()!!
//presenter.setupCategoryList(categoryList = category as ArrayList<Category>)
}
})
return category
}
}
My Category Activity class
val binding: ActivityCategoryBinding =
DataBindingUtil.setContentView(this#CategoryActivity, R.layout.activity_category)
val categoryViewModel =
ViewModelProviders.of(this#CategoryActivity).get(CategoryViewModel::class.java)
binding.categoryViewModel = categoryViewModel
categoryViewModel.getArrayList().observe(this#CategoryActivity, Observer { category ->
mAdapter = CategoryAdapter(this#CategoryActivity, categoryList = category )
recycler_category.layoutManager = LinearLayoutManager(applicationContext, OrientationHelper.VERTICAL, false)
recycler_category.adapter = mAdapter
recycler_category.setHasFixedSize(true)
})
My RecyclerView Adapter class
class CategoryAdapter(private val context: Context, private val categoryList: ArrayList<Category>?)
: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var mCategoryList: ArrayList<Category> = ArrayList()
private var mSourceList: ArrayList<Category> = ArrayList()
fun setupCategory(categoryList: ArrayList<Category>) {
mSourceList.clear()
mSourceList.addAll(categoryList)
search(query = "")
}
fun search(query: String) {
mCategoryList.clear()
mSourceList.forEach {
if (it.name.contains(query, ignoreCase = true)) {
mCategoryList.add(it)
}
}
notifyDataSetChanged()
}
fun sortByName() {
mCategoryList.sortBy { it.name }
notifyDataSetChanged()
}
fun sortByPrice() {
mCategoryList.sortBy { it.price }
notifyDataSetChanged()
}
fun filter() {
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is CategoryViewHolder) {
holder.bind(categoryModel = mCategoryList[position])
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val itemView = layoutInflater.inflate(R.layout.cell_category, parent, false)
return CategoryViewHolder(itemView = itemView)
}
override fun getItemCount(): Int {
return mCategoryList.count()
}
class CategoryViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
var mCategoryIcon: CircleImageView = itemView.findViewById(R.id.category_icon)
var mCategoryName: TextView = itemView.findViewById(R.id.category_name)
var mCategoryPrice: TextView = itemView.findViewById(R.id.category_price)
private var mCategoryType: TextView = itemView.findViewById(R.id.category_type)
fun bind(categoryModel: Category) {
categoryModel.icon.let { url ->
Picasso.with(itemView.context).load(url)
.into(mCategoryIcon)
}
mCategoryName.text = categoryModel.name
mCategoryPrice.text = categoryModel.price.toString()
mCategoryType.text = categoryModel.category
}
}
}
And my ViewModel class
class CategoryViewModel : ViewModel() {
var mutableLiveData = MutableLiveData<ArrayList<Category>>()
fun getArrayList(): MutableLiveData<ArrayList<Category>> {
mutableLiveData.value = CategoryClient().loadCategory() as ArrayList<Category>?
return mutableLiveData
}
}
Your data is not updated from asynchronous API call. Change you implementation like below to get updated data:
class CategoryViewModel : ViewModel() {
fun getArrayList(): MutableLiveData<ArrayList<Category>> {
return CategoryClient().loadCategory()
}
}
And your loadCategory
var mutableLiveData = MutableLiveData<ArrayList<Category>>()
fun loadCategory(): MutableLiveData<ArrayList<Category>> {
api.fetchAllCategory().enqueue(object : Callback<List<Category>> {
override fun onFailure(call: Call<List<Category>>, t: Throwable) {
}
override fun onResponse(call: Call<List<Category>>, response: Response<List<Category>>) {
mutableLiveData.postValue(response.body())
}
})
return mutableLiveData
}
And your adapter should be corrected to use single source
class CategoryAdapter(private val context: Context, private val mCategoryList: ArrayList<Category>?)
: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var mSourceList: ArrayList<Category> = ArrayList(mCategoryList)
.....
}
I am trying to show json data using retrofit library in kotlin
This is my Json:
[
{
"login": "mojombo",
"id": 1,
},
{
"login": "defunkt",
"id": 2,
}
]
My Main activity
call.enqueue(object : Callback<UserResponse> {
override fun onResponse(call: Call<UserResponse>, response: Response<UserResponse>) {
Log.e("list","list")
val countrylist = response.body()
for (size in response.body()) {
System.out.println(size.toString())
}
// var listOfMovies: List<UserResponse> = response.body()?.results!!
// myCustomAdapter = UserListAdapter(applicationContext, listOfMovies)
// recyclerView.setAdapter(myCustomAdapter)
progressBar.visibility = View.GONE
}
override fun onFailure(call: Call<UserResponse>?, t: Throwable?) {
progressBar.visibility = View.GONE
Log.e("list", t.toString())
}
})
This an app that I build in kotlin using retrofit and rxjava in the best way possible using a test API.
Model
data class Post( val userID:Int, val title:String, val body: String)
Retrofit Package
IMyApi interface
interface IMyApi {
#get:GET("posts")
val posts: Observable<List<Post>>
}
RetrofitClient Object class
object RetrofitClient {
val instance: Retrofit by lazy {
Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
Adapter Package
PostAdapter class
class PostAdapter(private val context: Context, private val postList: List<Post>)
:RecyclerView.Adapter<PostViewHolder>()
{
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
PostViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.post_item, parent, false)
return PostViewHolder(itemView)
}
override fun getItemCount(): Int {
return postList.size
}
override fun onBindViewHolder(holder: PostViewHolder, position: Int)
{
holder.userId.text = postList[position].userID.toString()
holder.title.text = postList[position].title
holder.body.text = StringBuilder(postList[position].body.substring(0,20))
.append("...").toString()
}
}
PostViewHolder class
class PostViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
var userId = itemView.txtID
var title = itemView.txtTitle
var body = itemView.txtBody
}
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var jsonApi: IMyApi
private var compositeDisposable: CompositeDisposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Init api
val retrofit = RetrofitClient.instance
jsonApi = retrofit.create(IMyApi::class.java)
// View
recycler_posts.layoutManager = LinearLayoutManager(this)
recycler_posts.setHasFixedSize(true)
fetchData()
}
private fun fetchData() {
compositeDisposable.add(jsonApi.posts
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { posts->displayData(posts)})
}
private fun displayData(posts: List<Post>?) {
val adapter = PostAdapter(this, posts!!)
recycler_posts.adapter = adapter
}
}
Using this as displayed above should help you solve your issue hopefully. Also when in the code you come across "recycler_posts". This is a id to the recycler added in activity_main. If you need me to include that let me know
That's what we have on our app
object GetFAQsAPI {
private val LOG_TAG = GetFAQsAPI.javaClass.simpleName
interface ThisCallback {
fun onSuccess(getFAQs: GetFAQs)
fun onFailure(failureMessage: String)
fun onError(errorMessage: String)
}
/* POST */
fun postData(jo: JsonObject, callback: GetFAQsAPI.ThisCallback) {
val call = Service.getService().get_faqs(jo)
call.enqueue(object : Callback<JsonObject> {
override fun onResponse(call: Call<JsonObject>, response: Response<JsonObject>) {
//Log.e(LOG_TAG, response.body().toString());
try {
if (response.body()?.get("success")!!.asBoolean) {
val gson = GsonBuilder().setPrettyPrinting().create()
val getFAQs = gson.fromJson(response.body(), GetFAQs::class.java)
callback.onSuccess(getFAQs)
} else {
Log.e(LOG_TAG, "else")
val error = response.body()!!.get("err").asString
callback.onError(error)
}
} catch (e: Exception) {
Log.e(LOG_TAG, "exception" + e.localizedMessage)
callback.onFailure(e.message!!)
}
}
override fun onFailure(call: Call<JsonObject>, t: Throwable) {
Log.e(LOG_TAG, "onFailure: " + t.message)
callback.onFailure(t.message!!)
}
})
}
}
That's how we call it from our fragment - getFAQs is the object parsed.
private fun getFAQsAPI() {
showLoading(true)
val jo = JsonObject().apply {
addProperty("faq_category", "admin")
}
GetFAQsAPI.postData(jo, object : GetFAQsAPI.ThisCallback {
override fun onSuccess(getFAQs: GetFAQs) {
Log.i(LOG_TAG, "onSuccess")
showLoading(false)
updateUI(getFAQs)
}
override fun onFailure(failureMessage: String) {
Log.e(LOG_TAG, failureMessage)
}
override fun onError(errorMessage: String) {
Log.e(LOG_TAG, errorMessage)
}
})
}
Hope that helps.
I'm using android architecture component in my project.So i used paging library for pagination, in my case i needed PageKeyedDataSource, but i could not able to get the loaded data back to the UI,
Codes are
DataSourceFactory.kt
class DataSourceFactory : DataSource.Factory<Int, Item>() {
private val mutableLiveData = MutableLiveData<SearchedItemsDataSource>()
private lateinit var feedDataSource: SearchedItemsDataSource
override fun create(): DataSource<Int, Item> {
feedDataSource = SearchedItemsDataSource()
mutableLiveData.postValue(feedDataSource)
return feedDataSource
}}
DataSource.kt
class SearchedItemsDataSource() : PageKeyedDataSource<Int, Item>() {
private var client: Api
init {
val logging = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor(logging)
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://api.stackexchange.com/2.2/")
.client(httpClient.build())
.build()
client = retrofit.create(Api::class.java)
}
override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Item>) {
val callClient = client.getAnswers(1, params.requestedLoadSize, "stackoverflow")
callClient.enqueue(object : Callback<StackApiResponse> {
override fun onResponse(call: Call<StackApiResponse>, response: Response<StackApiResponse>) {
if (response.isSuccessful && response.body() != null) {
println("loadInitial onResponse1111 :${response.isSuccessful} *** ${params.requestedLoadSize}")
val searchedItems = response.body() as StackApiResponse
callback.onResult(searchedItems.items, 0,searchedItems.items.size,null, 21)
println("loadInitial onResponse1111 :${response.isSuccessful} *** ${params.requestedLoadSize} *** ${searchedItems.items.size}")
} else {
println("loadInitial onResponse :${response.isSuccessful} *** ${response.message()}")
}
}
override fun onFailure(call: Call<StackApiResponse>, t: Throwable) {
t.printStackTrace()
println("loadInitial onFailure :${t.message} ${t.localizedMessage}")
}
})
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Item>) {
println("loadAfter " + params.key + " Count " + params.requestedLoadSize);
val callClient = client.getAnswers(params.key, params.requestedLoadSize, "stackoverflow")
callClient.enqueue(object : Callback<StackApiResponse> {
override fun onResponse(call: Call<StackApiResponse>, response: Response<StackApiResponse>) {
if (response.isSuccessful && response.body() != null) {
println("loadAfter onResponse :${response.isSuccessful} *** ${params.key}")
val nextKey = params.key + 1
val searchedItems = response.body() as StackApiResponse
callback.onResult(searchedItems.items, nextKey)
} else {
println("loadAfter onResponse :${response.isSuccessful} *** ${response.message()}")
}
}
override fun onFailure(call: Call<StackApiResponse>, t: Throwable) {
t.printStackTrace()
println("loadAfter onFailure :${t.message} ${t.localizedMessage}")
}
})
}
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Item>) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}}
ViewModel.kt
class MainViewModel : ViewModel() {
internal lateinit var itemList: LiveData<PagedList<Item>>
fun getPagedItems(): LiveData<PagedList<Item>> {
val executor = Executors.newFixedThreadPool(5)
val feedDataFactory = DataSourceFactory()
val pagedListConfig = PagedList.Config.Builder()
.setEnablePlaceholders(true)
.setInitialLoadSizeHint(20)
.setPageSize(20).build()
itemList = (LivePagedListBuilder(feedDataFactory, pagedListConfig)).build()
return itemList
}}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: MainViewModel
private lateinit var mAdapter: ItemAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
mAdapter = ItemAdapter(this)
binding.recyclerView.adapter = mAdapter
viewModel.getPagedItems().observe(this, Observer { items ->
if (items != null && items.isNotEmpty()) {
println("observe called 1 ${items.size}")
mAdapter.submitList(items)
} else {
println("observe called 2 ${items?.size}")
}
})
}
}
In your Adapter, you should not be managing the list manually since you are using PagedListAdapter.
In your #Override public int getItemCount() {} do:
#Override
public int getItemCount() {
return super.getItemCount()
}