android - 如何保存和恢复ListView的滚动位置和状态

标签 android listview file-upload android-viewholder

让我们看一下工作的截图,以便更好地理解问题:

  1. 我已经上传第一个列表项的图像到服务器 [i.e:- Thumbnail 1.png],见下图:

enter image description here

  1. 我使用 Localhostmyfile 文件夹下上传了图片:

enter image description here

  1. 当我向下滚动 ListView 时,得到这个 - 真正的痛苦来了,如您所见 Thumbnail 7,我没有点击在上面:

enter image description here

  1. 当我再次向上滚动 ListView 时,得到这样的东西 - 这让我很恼火,对于 Thumbnail 2,我做到了不要碰那个:

enter image description here

我认为这足以向您解释,什么我正在尝试做什么,正在发生什么以及在哪里我有问题

现在轮到你告诉我解决方案了,我该如何解决这个问题?

一些解释:

我已经将第一个列表项的图像上传到服务器(并且根据我的要求,我的图像状态为“已上传”并且上传按钮现在已禁用)但是当我向下/向上滚动 ListView 时,它显示了其中的任何一个项目上传的列表不是我上传的列表(我主要注意到可见的列表项)并重置最初上传到服务器的第一个列表项的状态...

所以在这里我只想使我最初上传的那个特定项目的上传状态稳定...而不是任何可见项目(那些还没有上传)

只影响 ListView ,服务器没有任何反应(只获取我上传的一张图片)

MainActivity.java:-

public class MainActivity extends Activity  {

    static ListView lstView;
    private Handler handler = new Handler();;

    static List <String> ImageList;
    String strPath;     

    int position ;

    static File f;
    File newFile;


    static File[] files ;
    static File  file ;

    ViewHolder holder;
    View v ;        

    String fileName;    

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);      

    setContentView(R.layout.activity_main);


    /*** Get Images from SDCard ***/
    ImageList = getSD();

    // ListView and imageAdapter
    lstView = (ListView) findViewById(R.id.listView);
    lstView.setAdapter(new ImageAdapter(this));

    }

    private List <String> getSD()
    {
        List <String> it = new ArrayList <String>();
        File f = new File ("/mnt/sdcard/mydata/");
        File[] files = f.listFiles ();

        for (int i = 0; i <files.length; i++)
        {
            File  file = files[i];
            Log.d("Count",file.getPath());
            it.add (file.getPath());
        }
        return it;
    }   

    static class ViewHolder {
        public ViewHolder(View convertView) {
            // TODO Auto-generated constructor stub
        }                

        TextView textName;
        ImageView thumbnail;
        TextView textStatus;
        Button btnUpload;            

    }  

     public class ImageAdapter extends BaseAdapter
        {
            public ImageAdapter(Context c)
            {

            }

            public int getCount() {
                // TODO Auto-generated method stub
                return ImageList.size();
            }

            public Object getItem(int position) {
                // TODO Auto-generated method stub
                return position;
            }

            public long getItemId(int position) {
                // TODO Auto-generated method stub
                return position;
            }

    public View getView(final int position, View convertView, ViewGroup parent) {
        // Avoid unneccessary calls to findViewById() on each row, which is expensive!

            holder = null;

            if (convertView == null) {
            convertView = getLayoutInflater().inflate(R.layout.adapter_main, null);
            holder = new ViewHolder(convertView);

            // Create a ViewHolder and store references to the children views
            holder.textName = (TextView) convertView.findViewById(R.id.textName);
            holder.thumbnail = (ImageView) convertView.findViewById(R.id.thumbnail);                
            holder.btnUpload = (Button) convertView.findViewById(R.id.btnUpload);
            holder.textStatus = (TextView) convertView.findViewById(R.id.textStatus);

            // The tag can be any Object, this just happens to be the ViewHolder
            convertView.setTag(holder);                
            } else {                    
            holder = (ViewHolder) convertView.getTag();             
            }

            strPath = ImageList.get(position).toString();

            // Get File Name
            fileName = strPath.substring( strPath.lastIndexOf('/')+1, strPath.length() );
            file = new File(strPath);
            @SuppressWarnings("unused")
            long length = file.length();
            holder.textName.setText(fileName);


            final BitmapFactory.Options options = new BitmapFactory.Options();

            Bitmap bm = BitmapFactory.decodeFile(strPath,options);
            holder.thumbnail.setImageBitmap(bm);       

            //btnUpload
            holder.btnUpload.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                    // Upload                           
                    startUpload(position);
                }
            });

            return convertView;

        }   
    }



            // Upload

            public void startUpload(final int position) {      

                Runnable runnable = new Runnable() {

                public void run() {

                    handler.post(new Runnable() {

                public void run() {

                    v = lstView.getChildAt(position - lstView.getFirstVisiblePosition());
                    holder = (ViewHolder) v.getTag();
                    holder.btnUpload.setEnabled(false);

                        new UploadFileAsync().execute(String.valueOf(position));   
                                }
                            });
                        }
                    };
                    new Thread(runnable).start();
                    }

                    // Async Upload
                    public class UploadFileAsync extends AsyncTask<String, Void, Void> {

                        String resServer;

                    protected void onPreExecute() {
                        super.onPreExecute();
                    }

                    @Override
                    protected Void doInBackground(String... params) {
                    // TODO Auto-generated method stub
                        position = Integer.parseInt(params[0]);

                        int bytesRead, bytesAvailable, bufferSize;
                        byte[] buffer;
                        int maxBufferSize = 1 * 1024 * 1024;
                        int resCode = 0;
                        String resMessage = "";

                        String lineEnd = "\r\n";
                        String twoHyphens = "--";
                        String boundary =  "*****";

                        // File Path
                        String strSDPath = ImageList.get(position).toString();

                        // Upload to PHP Script
                        String strUrlServer = "http://10.0.2.2/uploadFile.php";

                        try {
                            /** Check file on SD Card ***/
                            File file = new File(strSDPath);
                            if(!file.exists())
                            {   
                                resServer = "{\"StatusID\":\"0\",\"Message\":\"Please check path on SD Card\"}";
                                return null;
                            }

                        FileInputStream fileInputStream = new FileInputStream(new File(strSDPath));

                        URL url = new URL(strUrlServer);
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                            conn.setDoInput(true);
                            conn.setDoOutput(true);
                            conn.setUseCaches(false);
                            conn.setRequestMethod("POST");

                            conn.setRequestProperty("Connection", "Keep-Alive");
                            conn.setRequestProperty("Content-Type",
                                    "multipart/form-data;boundary=" + boundary);

                        DataOutputStream outputStream = new DataOutputStream(conn
                                .getOutputStream());
                            outputStream.writeBytes(twoHyphens + boundary + lineEnd);
                            outputStream
                            .writeBytes("Content-Disposition: form-data; name=\"filUpload\";filename=\""
                                    + strSDPath + "\"" + lineEnd);
                            outputStream.writeBytes(lineEnd);

                        bytesAvailable = fileInputStream.available();
                        bufferSize = Math.min(bytesAvailable, maxBufferSize);
                        buffer = new byte[bufferSize];

                        // Read file
                        bytesRead = fileInputStream.read(buffer, 0, bufferSize);

                        while (bytesRead > 0) {
                            outputStream.write(buffer, 0, bufferSize);
                            bytesAvailable = fileInputStream.available();
                            bufferSize = Math.min(bytesAvailable, maxBufferSize);
                            bytesRead = fileInputStream.read(buffer, 0, bufferSize);
                        }

                        outputStream.writeBytes(lineEnd);
                        outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

                        // Response Code and  Message
                        resCode = conn.getResponseCode();
                            if(resCode == HttpURLConnection.HTTP_OK)
                            {
                                InputStream is = conn.getInputStream();
                                ByteArrayOutputStream bos = new ByteArrayOutputStream();

                        int read = 0;
                        while ((read = is.read()) != -1) {
                            bos.write(read);
                        }

                        byte[] result = bos.toByteArray();
                            bos.close();

                        resMessage = new String(result);

                        }

                        Log.d("resCode=",Integer.toString(resCode));
                        Log.d("resMessage=",resMessage.toString());

                        fileInputStream.close();
                        outputStream.flush();
                        outputStream.close();

                        resServer = resMessage.toString();


                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }

                        return null;
                        }

                        protected void onPostExecute(Void unused) {
                            statusWhenFinish(position,resServer);
                            }

                        }


                    // When Upload Finish
                    @SuppressWarnings("unused")
                    protected void statusWhenFinish(int position, String resServer) {


                    /*** Default Value ***/
                    String strStatusID = "0" ;
                    String strError = "" ;

                    try {      

                    JSONObject c = new JSONObject(resServer);
                    strStatusID = c.getString("StatusID");
                    strError = c.getString("Message");
                    } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    }                                                                  

                    // prepare Status
                    if(strStatusID.equals("0"))
                    {                         
                        // When update Failed
                       holder.textStatus.setText("Failed");
                       holder.btnUpload.setEnabled(true);
                    }
                    else
                    {
                        holder.textStatus.setText("Uploaded");  
                        holder.btnUpload.setEnabled(false);
                    }

            }

}

最佳答案

引入如下结构:

/**
 * Introduce a class with below attributes to hold a state of each row in single
 * element
 * 
 */
public class MyData {
    /* Image url or path of image in single row */
    private String images;

    /* anme of image in single row */
    private String name;

    /* status ID of image in single row */
    private String statusID;

    /* message of image in single row */
    private String message;

    // Generate getters and setter
    public String getImages() {
        return images;
    }

    public void setImages(String images) {
        this.images = images;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getStatusID() {
        return statusID;
    }

    public void setStatusID(String statusID) {
        this.statusID = statusID;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

添加了适当的注释以理解代码。

//MyDataList是arrylist ArrayList(),需要在构造函数中初始化这个数据结构

  public View getView(int position, View convertView, ViewGroup parent) {

    MyData fields = MyDataList.get(position);
}

编辑:

我已经编辑了上面发布的代码,请看下面的代码我是如何使用 MyData 设置状态的

package com.example.trial;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {

    static ListView lstView;
    private Handler handler = new Handler();;
    static List<MyData> ImageList;
    String strPath;
    int position;
    File newFile;
    ViewHolder holder;
    View v;
    String fileName;
    ImageAdapter mAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        /*** Get Images from SDCard ***/
        ImageList = getSD();
        // ListView and imageAdapter
        lstView = (ListView) findViewById(R.id.listView);
        mAdapter = new ImageAdapter(this);
        lstView.setAdapter(mAdapter);

    }

    private List<MyData> getSD() {
        List<MyData> it = new ArrayList<MyData>();
        String root_sd = Environment.getExternalStorageDirectory().toString();
        File f = new File(root_sd + "/Download");
        File[] files = f.listFiles();
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            Log.d("Count", file.getPath());
            MyData data = new MyData();
            data.setImages(file.getPath());
            data.setStatusEnable(true);
            it.add(data);
        }
        return it;
    }

    static class ViewHolder {
        public ViewHolder(View convertView) {
            // TODO Auto-generated constructor stub
        }

        TextView textName;
        ImageView thumbnail;
        TextView textStatus;
        Button btnUpload;

    }

    public class ImageAdapter extends BaseAdapter {
        public ImageAdapter(Context c) {

        }

        public int getCount() {
            // TODO Auto-generated method stub
            return ImageList.size();
        }

        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        public View getView(final int position, View convertView,
                ViewGroup parent) {
            // Avoid unneccessary calls to findViewById() on each row, which is
            // expensive!

            holder = null;

            if (convertView == null) {
                convertView = getLayoutInflater().inflate(
                        R.layout.adapter_main, null);
                holder = new ViewHolder(convertView);

                // Create a ViewHolder and store references to the children
                // views
                holder.textName = (TextView) convertView
                        .findViewById(R.id.textName);
                holder.thumbnail = (ImageView) convertView
                        .findViewById(R.id.thumbnail);
                holder.btnUpload = (Button) convertView
                        .findViewById(R.id.btnUpload);
                holder.textStatus = (TextView) convertView
                        .findViewById(R.id.textStatus);

                // The tag can be any Object, this just happens to be the
                // ViewHolder
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.btnUpload.setEnabled(ImageList.get(position)
                    .isStatusEnable());
            holder.textStatus.setText(ImageList.get(position).getMessage());
            strPath = ImageList.get(position).getImages().toString();

            // Get File Name
            fileName = strPath.substring(strPath.lastIndexOf('/') + 1,
                    strPath.length());
            File file = new File(strPath);
            @SuppressWarnings("unused")
            long length = file.length();
            holder.textName.setText(fileName);

            final BitmapFactory.Options options = new BitmapFactory.Options();

            Bitmap bm = BitmapFactory.decodeFile(strPath, options);
            holder.thumbnail.setImageBitmap(bm);

            // btnUpload
            holder.btnUpload.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    // Upload
                    startUpload(position);
                }
            });

            return convertView;

        }
    }

    // Upload

    public void startUpload(final int position) {

        Runnable runnable = new Runnable() {

            public void run() {

                handler.post(new Runnable() {

                    public void run() {
                        v = lstView.getChildAt(position
                                - lstView.getFirstVisiblePosition());
                        holder = (ViewHolder) v.getTag();
                        synchronized (this) {
                            ImageList.get(position).setStatusEnable(false);
                            mAdapter.notifyDataSetChanged();
                        }

                        new UploadFileAsync().execute(String.valueOf(position));
                    }
                });
            }
        };
        new Thread(runnable).start();
    }

    // Async Upload
    public class UploadFileAsync extends AsyncTask<String, Void, Void> {

        String resServer;

        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(String... params) {
            position = Integer.parseInt(params[0]);
            int bytesRead, bytesAvailable, bufferSize;
            byte[] buffer;
            int maxBufferSize = 1 * 1024 * 1024;
            int resCode = 0;
            String resMessage = "";

            String lineEnd = "\r\n";
            String twoHyphens = "--";
            String boundary = "*****";

            // File Path
            String strSDPath = ImageList.get(position).getImages().toString();

            // Upload to PHP Script
            String strUrlServer = "http://mymasterpeice.comxa.com/uploadFile.php";

            try {
                /** Check file on SD Card ***/
                File file = new File(strSDPath);
                if (!file.exists()) {
                    resServer = "{\"StatusID\":\"0\",\"Message\":\"Please check path on SD Card\"}";
                    return null;
                }

                FileInputStream fileInputStream = new FileInputStream(new File(
                        strSDPath));

                URL url = new URL(strUrlServer);
                HttpURLConnection conn = (HttpURLConnection) url
                        .openConnection();
                conn.setDoInput(true);
                conn.setDoOutput(true);
                conn.setUseCaches(false);
                conn.setRequestMethod("POST");

                conn.setRequestProperty("Connection", "Keep-Alive");
                conn.setRequestProperty("Content-Type",
                        "multipart/form-data;boundary=" + boundary);

                DataOutputStream outputStream = new DataOutputStream(
                        conn.getOutputStream());
                outputStream.writeBytes(twoHyphens + boundary + lineEnd);
                outputStream
                        .writeBytes("Content-Disposition: form-data; name=\"filUpload\";filename=\""
                                + strSDPath + "\"" + lineEnd);
                outputStream.writeBytes(lineEnd);

                bytesAvailable = fileInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                buffer = new byte[bufferSize];

                // Read file
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);

                while (bytesRead > 0) {
                    outputStream.write(buffer, 0, bufferSize);
                    bytesAvailable = fileInputStream.available();
                    bufferSize = Math.min(bytesAvailable, maxBufferSize);
                    bytesRead = fileInputStream.read(buffer, 0, bufferSize);
                }

                outputStream.writeBytes(lineEnd);
                outputStream.writeBytes(twoHyphens + boundary + twoHyphens
                        + lineEnd);

                // Response Code and Message
                resCode = conn.getResponseCode();
                if (resCode == HttpURLConnection.HTTP_OK) {
                    InputStream is = conn.getInputStream();
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();

                    int read = 0;
                    while ((read = is.read()) != -1) {
                        bos.write(read);
                    }

                    byte[] result = bos.toByteArray();
                    bos.close();

                    resMessage = new String(result);

                }

                Log.d("resCode=", Integer.toString(resCode));
                Log.d("resMessage=", resMessage.toString());

                fileInputStream.close();
                outputStream.flush();
                outputStream.close();

                resServer = resMessage.toString();

            } catch (Exception ex) {
                ex.printStackTrace();
            }

            return null;
        }

        protected void onPostExecute(Void unused) {
            statusWhenFinish(position, resServer);
        }

    }

    // When Upload Finish
    @SuppressWarnings("unused")
    protected void statusWhenFinish(int position, String resServer) {

        /*** Default Value ***/
        String strStatusID = "0";
        String strError = "";

        try {

            JSONObject c = new JSONObject(resServer);
            strStatusID = c.getString("StatusID");
            strError = c.getString("Message");
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // // prepare Status
        if (strStatusID.equals("0")) {
            // When update Failed
            ImageList.get(position).setMessage("Failed");
            ImageList.get(position).setStatusEnable(true);
            mAdapter.notifyDataSetChanged();
        } else {
            ImageList.get(position).setMessage("Uploded");
            ImageList.get(position).setStatusEnable(false);
            mAdapter.notifyDataSetChanged();
        }

    }

    /**
     * Introduce a class with below attributes to hold a state of each row in
     * single element
     * 
     */
    public class MyData {
        /* Image url or path of image in single row */
        private String images;

        /* anme of image in single row */
        private String name;

        /* status ID of image in single row */
        private String statusID;

        /* message of image in single row */
        private String message;

        private boolean statusEnable;

        public boolean isStatusEnable() {
            return statusEnable;
        }

        public void setStatusEnable(boolean statusEnable) {
            this.statusEnable = statusEnable;
        }

        // Generate getters and setter
        public String getImages() {
            return images;
        }

        public void setImages(String images) {
            this.images = images;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getStatusID() {
            return statusID;
        }

        public void setStatusID(String statusID) {
            this.statusID = statusID;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

    }

}

关于android - 如何保存和恢复ListView的滚动位置和状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29114729/

相关文章:

如果数据发生变化,Flutter 如何更新 Listview.builder

java - listView 不显示“设计”选项卡中的项目,但显示在模拟器中

android:自定义 CursorAdapter 中的样式 ListView 项目

ruby-on-rails - 在 Rails 中将图像存储为模型

android - Web历史记录项目 : URL vs Original URL

java - 在android中使用JNI对 'multiply'的 undefined reference

android - 如何获取Android图库中图像的图像ID?

android - 在 Android 中升级 OpenSSL

angularjs - ng-switch 导致上传错误

php - jQuery 文件上传和获取 $_Files