【问题标题】:Images dissapearing while scrolling Listiew (Android Studio)滚动 Listview 时图像消失(Android Studio)
【发布时间】:2020-04-17 22:15:28
【问题描述】:

伙计们。
我对编程和 Android 编程完全陌生,我有一个问题。我从 MySQL 数据库中获取图像作为 InputStream。然后我有适配器,我将从数据库中获得的数据加载到相应的对象。万岁,listView 已创建,一切看起来都不错!但是......当我向下/向上滚动时,我的图像消失了。我读过 listView 回收对象,但问题是我不知道/不明白如何解决这个问题:///
请帮帮我!!

SHORT:滚动时列表视图中的图像消失。太多新手不知道如何解决它:/

事件类

public class Event {

    private int id;
    private String title;
    private Date date;
    private String place;
    private String genre;
    private String description;
    private Double price;

    public Event(int id, String title, Date date, String place, String genre, String description, Double price, InputStream image) {
        this.id = id;
        this.title = title;
        this.date = date;
        this.place = place;
        this.genre = genre;
        this.description = description;
        this.price = price;
        this.image = image;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getPlace() {
        return place;
    }

    public void setPlace(String place) {
        this.place = place;
    }

    public String getGenre() {
        return genre;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public InputStream getImage() {
        return image;
    }

    public void setImage(InputStream image) {
        this.image = image;
    }

    private InputStream image;

}

适配器类

    public class EventAdapter extends BaseAdapter {

    LayoutInflater mInflater;
    ArrayList<Event> data;

    public EventAdapter(Context c, ArrayList<Event> d){
        mInflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.data = d;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    // This is where data is assigned to coresponding fields in event_layout
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // Hooks
        View view = mInflater.inflate(R.layout.event_layout, null);
        TextView eventName = (TextView) view.findViewById(R.id.eventName);
        TextView dateYear = (TextView) view.findViewById(R.id.dateYear);
        TextView dateDay = (TextView) view.findViewById(R.id.dateDay);
        ImageView image = (ImageView) view.findViewById(R.id.eventImage);

        // Changing date format
        SimpleDateFormat sdf = new SimpleDateFormat("MMM dd yyyy");
        String date = sdf.format(data.get(position).getDate());

        // Extracting date into seprate vars
        String year = date.substring(8);
        String day = date.substring(0, 1).toUpperCase() + date.substring(1, 3) + "." + date.substring(4, 7) + "d.";
        // making Bitmap from InputStream
        Bitmap bmp = BitmapFactory.decodeStream(data.get(position).getImage());

        eventName.setText(data.get(position).getTitle());
        dateYear.setText(year);
        dateDay.setText(day);

        image.setImageBitmap(bmp);

        return view;
    }
}

EventsPage 类

    public class EventsPage extends AppCompatActivity {

    private EventAdapter eventAdapter;
    private Context thisContext;
    private ListView eventsListView;
    private TextView progressBar;
    private ArrayList<Event> events = new ArrayList<Event>();

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // Set status bar color to main_green
        if(Build.VERSION.SDK_INT >= 21){
            Window window = this.getWindow();
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                window.setStatusBarColor(this.getResources().getColor(R.color.main_green_color , this.getTheme()));
            }
        }

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_events_page);

        Resources res = getResources();
        eventsListView = (ListView) findViewById(R.id.eventsListView);
        progressBar = (TextView) findViewById(R.id.progressBar);
        thisContext = this;

        progressBar.setText("");

        GetData data = new GetData();
        data.execute("");


    }

    public class GetData  extends AsyncTask<String, String, String> {
        private String msg;
        private ArrayList<Event> bkc_events = new ArrayList<>();
        private ArrayList<Event> tic_events = new ArrayList<>();

        @Override
        protected void  onPreExecute(){
            progressBar.setText("Connecting to database...");
        }

        @RequiresApi(api = Build.VERSION_CODES.N)
        @Override
        protected String doInBackground(String... strings) {

            Connection conn = null;
            Statement stmt = null;

            try {
                Class.forName(DBstrings.JDBC_DRIVER);
                conn = DriverManager.getConnection(DBstrings.URL, DBstrings.USERNAME, DBstrings.PASSWORD);

                // Get BKC events
                stmt = conn.createStatement();
                String query = "SELECT * from `bkc_event` ORDER by `date` ASC";
                ResultSet res = stmt.executeQuery(query);

                while(res.next()){
                    Event temp = new Event(res.getInt("ID"), res.getString("title"),
                            res.getDate("date"), res.getString("place"),
                            res.getString("genre"), res.getString("description"),
                            res.getDouble("price"), res.getBinaryStream("image"));
                    this.bkc_events.add(temp);
                }

                res.close();

                // Get TIC events
                query = "SELECT * from `tic_event` ORDER by `date` ASC";
                res = stmt.executeQuery(query);

                while(res.next()){
                    Event temp = new Event(res.getInt("ID"), res.getString("title"),
                            res.getDate("date"), res.getString("place"),
                            res.getString("genre"), res.getString("description"),
                            res.getDouble("price"), res.getBinaryStream("image"));
                    tic_events.add(temp);
                }

                res.close();
                stmt.close();
                conn.close();

                msg = "Process Completed";
                PutDataTogether(bkc_events, tic_events);

            } catch (ClassNotFoundException ex) {
                msg = "Class not found ERROR";
                Log.e("ClassNotFound", ex.getMessage());
            } catch (SQLException ex) {
                msg = "SQL exceltion";
                Log.e("SQL:", ex.getMessage());
            } finally {
                try {
                    if(stmt != null)
                        stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                try {
                    if(conn != null)
                        conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

            return null;
        }

        // Combine data 2 sets into 1 set
        @RequiresApi(api = Build.VERSION_CODES.N)
        private void PutDataTogether(ArrayList<Event> bkc, ArrayList<Event> tic){

            events.addAll(bkc);

            for (Event t: tic) {
                // counter for showing redundancy
                int counter = 0;
                for(Event r: events){
                    // Check if title and date is the same if so - increase counter by 1
                    if(t.getTitle().toLowerCase().equals(r.getTitle().toLowerCase()) &&
                            t.getDate().equals(r.getDate()))
                        counter++;
                }
                // if counter == 0, then we can add event to final result set
                if(counter == 0)
                    events.add(t);
            }
            events.sort(Comparator.comparing(Event::getDate));
        }

        // To show the data
        @Override
        protected void onPostExecute(String msg){
            progressBar.setText(this.msg);

            /*new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    progressBar.setVisibility(View.INVISIBLE);
                }
            }, 1500);  */


            // We have stuff to display
            if(events.size() > 0){
                eventAdapter = new EventAdapter(thisContext, events);
                eventsListView.setAdapter(eventAdapter);
            }

        }

    } // END of GetDataEvents class

}   // END of EventsPage

问题:
Picture before scrolling
Picture after scrolling down and then back up

【问题讨论】:

    标签: java android database imageview inputstream


    【解决方案1】:

    问题出在适配器的getView() 方法中。在ListView 中回收意味着,已经有一个现有的View 将用于显示您的值,因此您不能夸大新的值。更改您的代码,如:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    
        // Hooks
        View view = convertView;
        if (view == null) {
            view = mInflater.inflate(R.layout.event_layout, null);
        }
    
        TextView eventName = (TextView) view.findViewById(R.id.eventName);
        TextView dateYear = (TextView) view.findViewById(R.id.dateYear);
        TextView dateDay = (TextView) view.findViewById(R.id.dateDay);
        ImageView image = (ImageView) view.findViewById(R.id.eventImage);
    
        // Changing date format
        SimpleDateFormat sdf = new SimpleDateFormat("MMM dd yyyy");
        String date = sdf.format(data.get(position).getDate());
    
        // Extracting date into seprate vars
        String year = date.substring(8);
        String day = date.substring(0, 1).toUpperCase() + date.substring(1, 3) + "." + date.substring(4, 7) + "d.";
        // making Bitmap from InputStream
        Bitmap bmp = BitmapFactory.decodeStream(data.get(position).getImage());
    
        eventName.setText(data.get(position).getTitle());
        dateYear.setText(year);
        dateDay.setText(day);
    
        image.setImageBitmap(bmp);
    
        return view;
    }
    

    请注意,我只更改了方法的前 4 行以使用来自 ListView 的提供的视图,并且仅在没有可重用的现有视图时膨胀一个新的。

    【讨论】:

    • 嗨!感谢您的通知! ^^ 我添加了代码(您已修复),但问题仍然存在:/
    • 我读过LruCache,但我不明白如何使用它以及如何设置它:|
    • 这可能会解决您的问题。但是,与其自己实现 LruCache,我强烈建议您使用像 Glide 这样的 Image-Loading-Library。查看此链接:raywenderlich.com/… 如果它解决了您的问题,请告诉我,我会将其包含在我的答案中。
    • 还有一件事。我看到他们使用图像的 URL,但没有 URL:/ 在数据库中图像保存为 LONGBLOB(因为我正在使用我创建的桌面应用程序将它们上传到数据库).. 有没有办法获取 URL Blob 或将 InputStream 转换为图像 URL?谢谢! ?
    • 除了在Glide的加载函数中放一个url,还可以放一个byte[],当你从数据库中加载一个blob时,你会得到什么。
    猜你喜欢
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多