Base Adapter 中的 notifyDatasetChanged 问题

Problem with notifyDatasetChanged in Base Adapter

我在使用 BaseAdapter 的 notifyDataSetChanged 方法时遇到问题。我想我真的不明白它的工作原理。我想在视图列表中添加一个新项目,以在上传图像时显示加载屏幕。图片上传后,我删除了该项目并调用了方法,但我收到了错误消息,我不明白为什么。


import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Build
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.support.v4.app.ActivityCompat
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.Toast
import com.google.android.gms.tasks.OnSuccessListener
import com.google.android.gms.tasks.Task
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.storage.FirebaseStorage
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_login.*
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.add_ticket.*
import kotlinx.android.synthetic.main.add_ticket.view.*
import kotlinx.android.synthetic.main.tweets_ticket.view.*
import java.io.ByteArrayOutputStream
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap

class MainActivity : AppCompatActivity() {
    private var listofTweets = ArrayList<Ticket>()
    var adapter:TweetsAdapter? = null
    private val PICK_IMG_CODE:Int = 123
    var myEmail:String? = null
    var downloadUrl:String? = null
    private var database = FirebaseDatabase.getInstance()
    private var myRef = database.reference
    var userID:String? = null
    private val READIMAGE:Int = 253

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var b:Bundle = intent.extras
        myEmail = b.getString("email")
        userID = b.getString("uid")

        listofTweets.add(Ticket("1", "My first tweet", "", "add"))
        listofTweets.add(Ticket("2", "My third tweet", "https://firebasestorage.googleapis.com/v0/b/fir-demoapp-8edf3.appspot.com/o/imagesPost%2F160819173436.jpg?alt=media&token=29ac687e-0936-49d8-a42f-50ab0e751208", "normal"))
        //listofTweets.add(Ticket("3", "My fourth tweet", "gs://fir-demoapp-8edf3.appspot.com/imagesPost/160819173436.jpg", "normal"))
        //listofTweets.add(Ticket("4", "My fifth tweet", "http://i.imgur.com/DvpvklR.png", "normal"))

        var adapter = TweetsAdapter(this, listofTweets)
        lvTweets.adapter = adapter
        loadPost()

    }

    inner class TweetsAdapter:BaseAdapter{
        var listOfTweetsAdapter = ArrayList<Ticket>()
        var context:Context? = null
        constructor(context:Context, listOfTweetsAdapter:ArrayList<Ticket>):super(){
            this.context = context
            this.listOfTweetsAdapter = listOfTweetsAdapter
        }

        override fun getCount(): Int {
            return listofTweets.size
        }

        override fun getItem(p0: Int): Any {
            return listofTweets[p0]
        }

        override fun getItemId(p0: Int): Long {
            return p0.toLong()
        }

        override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
            var tweet = listOfTweetsAdapter[p0]
            if(tweet.tweetPersonUid.equals("add")) {
                //Load add ticket
                var myView = layoutInflater.inflate(R.layout.add_ticket, null)
                myView.ivAttach.setOnClickListener {
                    //loadImage()
                    checkPermission()
                }
                myView.ivPost.setOnClickListener {
                    //Upload to the server
                    myRef.child("posts").push().setValue(
                        PostInfo(
                            userID.toString(), myView.etPost.text.toString(), downloadUrl.toString()
                        )
                    )
                    myView.etPost.setText("")
                }
                return myView
            } else if (tweet.tweetPersonUid.equals("loading")) {
                var myView = layoutInflater.inflate(R.layout.loading_ticket, null)
                return myView
            } else {
                //Load tweet ticket
                var myView = layoutInflater.inflate(R.layout.tweets_ticket, null)
                myView.txt_tweet.setText(tweet.tweetText)
                myView.txtUserName.setText(tweet.tweetPersonUid)
                Picasso.get().load(tweet.tweetImageUrl).into(myView.tweet_picture)

                myRef.child("Users").child(tweet.tweetPersonUid!!)
                    .addValueEventListener(object:ValueEventListener{
                        override fun onDataChange(p0: DataSnapshot) {
                            try {
                                var td = p0!!.value as HashMap<String, Any>
                                for (key in td.keys) {
                                    var userInfo = td[key] as String
                                    if(key.equals("profileImage")) {
                                        Picasso.get().load(userInfo).into(myView.picture_path)
                                    } else {
                                        myView.txtUserName.setText(userInfo)
                                    }

                                }
                            } catch (ex:Exception) {

                            }
                        }

                        override fun onCancelled(p0: DatabaseError) {
                            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                        }
                    })

                return myView
            }
        }
    }

    fun loadImage() {
        var intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
        startActivityForResult(intent, PICK_IMG_CODE)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if(requestCode == PICK_IMG_CODE && resultCode == Activity.RESULT_OK && data != null) {

                val selectedImage = data.data
                val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
                val cursor = contentResolver.query(selectedImage, filePathColumn, null, null, null)
                cursor.moveToFirst()
                val columnIndex = cursor.getColumnIndex(filePathColumn[0])
                val picturePath = cursor.getString(columnIndex)
                cursor.close()
                uploadImage(BitmapFactory.decodeFile(picturePath))

        }
    }

    fun uploadImage(bitmap:Bitmap){
        listofTweets.add(0, Ticket("0","him","url", "loading"))
        adapter!!.notifyDataSetChanged()

        val storage = FirebaseStorage.getInstance()
        var storageRef = storage.getReferenceFromUrl("gs://fir-demoapp-8edf3.appspot.com/")
        val df = SimpleDateFormat("ddMMyyHHmmss")
        val dataObj = Date()
        val imgPath = df.format(dataObj) + ".jpg"
        val imgRef = storageRef.child("imagesPost/" + imgPath)
        val baos = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
        val data = baos.toByteArray()
        val uploadTask = imgRef.putBytes(data)
        uploadTask.addOnFailureListener{
            Toast.makeText(applicationContext, it.toString(), Toast.LENGTH_LONG).show()
        }.addOnSuccessListener { taskSnapshot ->
            imgRef.downloadUrl.addOnCompleteListener() {taskSnapshot ->
                downloadUrl = taskSnapshot.result.toString()
                //listofTweets.removeAt(0)
                //adapter!!.notifyDataSetChanged()
            }

        }
    }

    fun loadPost(){
        myRef.child("posts")
            .addValueEventListener(object:ValueEventListener{
                override fun onDataChange(p0: DataSnapshot) {
                    try {
                        listofTweets.clear()
                        listofTweets.add(Ticket("1", "My first tweet", "", "add"))
                        var td = p0!!.value as HashMap<String, Any>
                        for (key in td.keys) {
                            var post = td[key] as HashMap<String, Any>
                            listofTweets.add(
                                Ticket(key,
                                post["text"] as String,
                                post["img"] as String,
                                post["userUID"] as String)
                            )
                        }
                        adapter!!.notifyDataSetChanged()
                    } catch (ex:Exception) {

                    }
                }

                override fun onCancelled(p0: DatabaseError) {
                    TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                }
            })
    }

    fun checkPermission() {
        if(Build.VERSION.SDK_INT >= 23) {
            if(ActivityCompat.checkSelfPermission(this,
                    android.Manifest.permission.READ_EXTERNAL_STORAGE) !=
                PackageManager.PERMISSION_GRANTED) {
                requestPermissions(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), READIMAGE)
                return
            }
        }

        loadImage()
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        when(requestCode) {
            READIMAGE -> {
                if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {loadImage()}
                else {Toast.makeText(this, "Cannot acces your images", Toast.LENGTH_LONG).show()}
            } else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        }
    }
}

并且错误日志是(第 172 行是适配器!!.notifyDataSetChanged()):

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=123, result=-1, data=Intent { dat=content://com.google.android.apps.photos.contentprovider/-1/1/content://media/external/images/media/113490/ORIGINAL/NONE/549404385 flg=0x1 clip={text/uri-list U:content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F113490/ORIGINAL/NONE/549404385} }} to activity {com.example.twitter/com.example.startup.MainActivity}: kotlin.KotlinNullPointerException
        at android.app.ActivityThread.deliverResults(ActivityThread.java:4363)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:4405)
        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1811)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6694)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: kotlin.KotlinNullPointerException
        at com.example.startup.MainActivity.uploadImage(MainActivity.kt:172)
        at com.example.startup.MainActivity.onActivityResult(MainActivity.kt:165)
        at android.app.Activity.dispatchActivityResult(Activity.java:7454)
        at android.app.ActivityThread.deliverResults(ActivityThread.java:4356)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:4405) 
        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1811) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6694) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 

提前致谢。

您遇到空指针异常。

// You have this class member
var adapter:TweetsAdapter? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // During on create, you are creating the adapter
    // However, you are holding the adapter in a local variable
    var adapter = TweetsAdapter(this, listofTweets)
}

fun uploadImage(bitmap:Bitmap){
    // Then, here, when you try to read the adapter, you are reading
    // the class member adapter (which is still null)
    adapter!!.notifyDataSetChanged()
}

为了修复空指针,请更新您的 onCreate 方法:

发件人:

var adapter = TweetsAdapter(this, listofTweets)

收件人:

this.adapter = TweetsAdapter(this, listofTweets)