Почему Android выдает ошибку «Попытка вызвать виртуальный метод по нулевой ссылке на объект», когда объект определенно не равен нулю? - PullRequest
0 голосов
/ 11 ноября 2019

У меня есть производный тип RecyclerView.Adapter, который должен загружать изображения на устройство через http. С этой целью я передаю ему ContentDownloadService, который расширяет IntentService.

Так что в моем MainActivity.kt я делаю это:

class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {

    private val Issues: ArrayList<Issue> = ArrayList<Issue>()

    private val downloadService: ContentDownloadService = ContentDownloadService()


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        loadConfiguration();
        val issueCards: RecyclerView = findViewById(R.id.issues_list)
        issueCards.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
        issueCards.adapter = IssueAdapter(Issues.toTypedArray(), this, downloadService)

    }
}

ContentDownloadService является довольно общим IntentService - насколько я знаю, это не очень актуально, потому что оно никогда не вызывается.

В IssueAdapter мы делаем это:

class IssueAdapter(private var issues: Array<Issue>, private val context: Context, private val downloadService: ContentDownloadService) : RecyclerView.Adapter<IssueAdapter.IssueViewHolder>() {


    class IssueViewHolder(public val cardView: CardView) : RecyclerView.ViewHolder(cardView)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int ) : IssueAdapter.IssueViewHolder {
        val issueView = LayoutInflater.from(parent.context).inflate(R.layout.issue_card_view, parent, false)as CardView;
        return IssueViewHolder(issueView);
    }

    override fun onBindViewHolder(holder: IssueViewHolder, position: Int) {
        val issueView:CardView = holder.cardView
        val title : TextView = issueView.findViewById(R.id.issue_title)
        val image: ImageView = issueView.findViewById(R.id.issue_cover_image))
        title.text = issues[position].title
        description.text = issues[position].description
        date.text = format.format(issues[position].date)
        if ( issues[position].imagePath != null) {
            downloadImage(position)
        }
    }

 private fun downloadImage( position : Int ){
        val downloadIntent = Intent()
        val resultReceiver =  object: ResultReceiver(Handler()){
            override fun onReceiveResult(resultCode: Int, bundleResultData : Bundle)
            {
                if ( resultCode == 0 ) {
                    issues[position].imagePath = bundleResultData.getString("path")
                }
            }
        };
        downloadIntent.putExtra(ContentDownloadService.IMAGE, issues[position].imagePath)
        downloadIntent.putExtra(ContentDownloadService.RECEIVER, resultReceiver)
        downloadService.startActivity(downloadIntent);
    }
}

Когда я пытаюсь запустить этов отладчике я получаю следующее сообщение:

    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.content.Context.startActivity(android.content.Intent)' on a null object reference
        at android.content.ContextWrapper.startActivity(ContextWrapper.java:379)
        at com.myapp.models.IssueAdapter.downloadImage(IssueAdapter.kt:72)

Подключение к отладчику показывает, что downloadService определенно является реальным объектом при его вызове.

Почему Android вызывает мой сервис как ноль при вызове, но показывает его как правильный в отладчике?

Ответы [ 2 ]

0 голосов
/ 11 ноября 2019

startActivity - это асинхронный метод, поэтому вы, скорее всего, теряете область действия вашего IntentService, прежде чем он сможет запустить действие. Вы можете попробовать сделать

downloadService.applicationContext.startActivity(downloadIntent);

Однако вам следует подумать о переосмыслении всего вашего подхода здесь. Обычно вы хотите запустить действие только из другого действия. Если ваше приложение находится на переднем плане и вызывается, система, скорее всего, вылетит с ошибкой, говорящей о том, что действия, не запущенные другими действиями, должны иметь добавленный флаг NEW_TASK. Причина в том, что вы будете запускать свою деятельность вне контекста вашего текущего пользовательского интерфейса и, следовательно, убьете текущую задачу и повторно запустите ее с предоставленной активностью.

0 голосов
/ 11 ноября 2019

С этой целью я передаю ему ContentDownloadService, который расширяет IntentService.

Вы НИКОГДА не должны создавать объекты каркаса Android самостоятельно, потому что они содержат много внутреннего состояния, которое будетнеинициализирован, если они созданы таким образом. Создав его с помощью val downloadService: ContentDownloadService = ContentDownloadService(), можно оставить неустановленной внутреннюю переменную Context, которая вызывает вашу ошибку.

...