Доступ к Twitter REST API работает только в mainActivity, но почему?

Я действительно запутался, и мне нужна ваша помощь! Это всего лишь мое второе приложение, и я впервые работаю с REST API. Я просто пытаюсь отобразить некоторую информацию о пользователе, такую ​​как имя и изображение профиля. Он отлично работает, когда я использую код в основном действии, но как только я использую для него другой класс, вызов API терпит неудачу, и код очень похож, поэтому я ничего не знаю. Поскольку Twitter использует Retrofit в своем собственном руководстве, я также использую его.

Мой класс, расширяющий TwitterApiClient, файл также включает интерфейс для пользовательской службы:

import android.util.Log
import com.twitter.sdk.android.core.*
import com.twitter.sdk.android.core.models.User
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query

class MyTwitterApiClient(session: TwitterSession) : TwitterApiClient(session) {

    fun getCustomService() : GetUsersShowAPICustomService {
        return getService(GetUsersShowAPICustomService::class.java)
    }

}

interface GetUsersShowAPICustomService {
    @GET("/1.1/users/show.json")
    fun show(@Query("user_id") userId: Long) : Call<User>
}

Мой метод в MainActivity выглядит так:

private fun loadTwitterAPI(userID: Long) {
        MyTwitterApiClient(session).getCustomService().show(userID).enqueue(object : Callback<User>() {
            override fun success(result: Result<User>?) {
                text.text = (
                        "Name: "+result!!.data.name
                                +"\nLocation: "+result!!.data.location
                                +"\nFriends: "+result!!.data.friendsCount
                        )

                Picasso.with(baseContext).load(result!!.data.profileImageUrl).resize(250, 250).into(imageView)
            }

            override fun failure(exception: TwitterException?)  {

            }
        })

    }

Это отлично работает, но я не хочу, чтобы сам вызов был в моей основной деятельности, и я создал сопутствующий объект в своем классе, расширяющий TwitterApi, который должен просто вызываться с параметром TwitterSession в качестве параметра, и он должен возвращать объект класса Пользователь, который содержит все важные данные.

Сопутствующий объект внутри класса MyTwitterApiClient выглядит следующим образом:

companion object {
        fun start(session: TwitterSession): User {
            val userID = session.userId
            var data: User? = null

            MyTwitterApiClient(session).getCustomService().show(userID).enqueue(object : Callback<User>() {
                override fun success(result: Result<User>?) {
                    data = result!!.data
                }

                override fun failure(exception: TwitterException?) {
                    throw exception!!
                }
            })

            return data!!
        }
    }

Новый метод в MainActivity выглядит так:

private fun loadTwitterAPI(userID: Long) {
val t = MyTwitterApiClient.start(session)
        text.text = (
                "Name: "+t.name
                        +"\nLocation: "+t.location
                        +"\nFriends: "+t.friendsCount
                )

        Picasso.with(baseContext).load(t.profileImageUrl).resize(250, 250).into(imageView)
}

В ходе тестирования я обнаружил, что ни метод успеха, ни метод отказа не вызываются. И я вообще не понимаю, почему он не вызывает никакого метода и просто не работает.

Если кто-то здесь уже работал с чем-то подобным или у него есть совет для меня, это было бы очень полезно!

Привет

Кстати: ошибка, которая в конце концов приводит к сбою моего приложения, представляет собой исключение NullPointerException, поскольку метод Success не вызывается, и в конце возвращается null.

Вставить в мои файлы:

Привет, Чак, не могли бы вы поделиться своим полным кодом на github, пожалуйста?

Rahul Shukla 09.05.2019 13:54

Он будет содержать мой ключ Twitter API, поэтому я не могу загрузить весь проект, но я могу мгновенно опубликовать ссылки pastebin на все мои файлы.

KITRIK 09.05.2019 13:58

Вы можете удалить ключ API, в любом случае это не проблема!

Rahul Shukla 09.05.2019 13:59

Теперь я добавил ссылки Pastebin. Мой проект не содержит ничего другого, пока я застрял в этой проблеме...

KITRIK 09.05.2019 14:09
0
4
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хорошо, начиная с вашего кода:

fun start(session: TwitterSession): User {
        val userID = session.userId
        var data: User? = null

        MyTwitterApiClient(session).getCustomService().show(userID).enqueue(object : Callback<User>() {
            override fun success(result: Result<User>?) {
                data = result!!.data
            }

            override fun failure(exception: TwitterException?) {
                throw exception!!
            }
        })

        return data!!
    }

Здесь вы возвращаете data, как будто это было назначено. Ваш TwitterApiClient выполняет асинхронную задачу, поэтому данные из data = result!!.data не будут правильно считаны из

text.text = (
            "Name: "+t.name
                    +"\nLocation: "+t.location
                    +"\nFriends: "+t.friendsCount
            )

Потому что t это null тогда. Его данные еще не установлены. Это будет когда-нибудь в будущем в асинхронном обратном вызове success().

Похоже, ваша основная проблема связана с тем, как работать с асинхронными задачами и как уведомлять о результатах. Много источников об этом. LiveData, RxJava, EventBus могут быть лидами.

Кстати, причина, по которой ваш код работал в MainActivity, заключалась в том, что вы устанавливали текст после того, как пришел результат (в success()), поэтому t было приятно читать.

Удачи и приятного обучения!

Я также подумал об этом и реализовал цикл while для тестирования, который заставлял основной поток спать в течение 1 секунды, прежде чем возвращать данные, если данные равны нулю, но он просто продолжал спать. В любом случае, спасибо за ваш ответ, он проясняет мою проблему.

KITRIK 09.05.2019 14:24

И кое-что, чтобы не выглядеть полным неудачником: в моем первом приложении я действительно работал с AsyncTask, и это было очень просто, но Retrofit — это совсем другое. Я просто хотел сделать это как можно быстрее и мало читал о модернизации, а просто следил за новостями из твиттера. Извините за это и извините, что отняли ваше время!

KITRIK 09.05.2019 14:34

AsyncTask снимает данные в onPostExecute в основном потоке, поэтому вам не пришлось играть с проблемами потоков. Не жалей, я был там. Это большая веха, чтобы перейти и понять многопоточность. Мой совет: не используйте AsynTask, изучите многопоточность. Удачного кодирования :)

shkschneider 09.05.2019 14:46

Спасибо за совет! Я знаю основы многопоточности, но недостаточно глубоко, как кажется... Теперь я углублюсь в это!

KITRIK 09.05.2019 14:56

Другие вопросы по теме