溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

使用ListView時的幾個BUG與相應(yīng)的優(yōu)化

發(fā)布時間:2020-06-07 14:35:06 來源:網(wǎng)絡(luò) 閱讀:497 作者:Android_smile 欄目:移動開發(fā)

package com.example.ex01_1;


import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLConnection;

import java.util.ArrayList;

import java.util.HashMap;


import android.os.AsyncTask;

import android.os.Bundle;

import android.os.Environment;

import android.app.Activity;

import android.app.AlertDialog;

import android.app.Notification;

import android.app.NotificationManager;

import android.content.Context;

import android.content.DialogInterface;

import android.database.CursorJoiner.Result;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.Menu;

import android.view.MenuItem;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.ViewGroup;

import android.widget.ArrayAdapter;

import android.widget.BaseAdapter;

import android.widget.Button;

import android.widget.ImageView;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.TextView;

import android.widget.Toast;


public class MainActivity<E> extends Activity 

{

    private ArrayList<String> dataList = new ArrayList<String>();

    private ArrayList<String> fileurl = new ArrayList<String>();

    private MyAdapater myadapater;

    // String PATH = "http://192.168.56.1:8080/server/";

    String PATH = "http://192.168.56.1:8080/server/";

    private ListView listView;

    

/**

問題:圖片下載完成,上下滑動ListView,圖片重新下載

    原因:上下滑動,觸發(fā)getView()方法,新建異步任務(wù),重新下載

    解決:創(chuàng)建一個容器,保存已經(jīng)下載的Bitmap對象

    為了防止重復(fù)下載,把以及下載的圖片放在imgmap這個容器中

*/


HashMap<String, Bitmap> imgmap = new HashMap<String, Bitmap>();

/**

* 問題:下載過程中,上下滑動ListView,等待下載完成,圖片多次下載

        原因:上下滑動ListView,觸發(fā)getView()方法,判斷圖片還未下載完成,創(chuàng)

        建新的異步任務(wù).

        解決:創(chuàng)建一個容器保存已經(jīng)開始執(zhí)行的AsyncTask對象

        創(chuàng)建一個容器用于保存已經(jīng)開始的異步任務(wù)

*/


    HashMap<String, ImgAsy> asymap = new HashMap<String, ImgAsy>();

/**問題是:某一行下載完成后,上下滑動ListView, 其他未點(diǎn)擊下載的行會出現(xiàn)前面?zhèn)€行的狀態(tài)。

      引用容器保存文件下載狀態(tài),

      我們通過下載狀態(tài)的區(qū)別來更新控件的狀態(tài),得以解決這個問題。創(chuàng)建一個容器用來保存當(dāng)前行的文件的下載狀態(tài),用來解決文件下載時,復(fù)用View帶來的Bug

*/

//

    HashMap<Integer, Boolean> stateMap = new HashMap<Integer, Boolean>();


    @Override

    protected void onCreate(Bundle savedInstanceState) 

    {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        // 首先找到activity_mian.xml里面的listView1


        listView = (ListView) findViewById(R.id.listView1);

        myadapater = new MyAdapater();

        listView.setAdapter(myadapater);

        // 添加圖片

        for (int i = 1; i < 16; i++) 

        {

             dataList.add(PATH + "ic" + i + ".png");

        }

        // 添加文件

             for (int i = 1; i < 16; i++) 

        {

             fileurl.add(PATH + "ic" + i + ".rar");

        }

    }

        

        // 得到一段保存地址

        private String getSavePath(String fileurl)

         {

            String sdcard = Environment.getExternalStorageDirectory() + "";

            // 截取一段地址

            int lastIndexOf = fileurl.lastIndexOf("/");

            String savename = fileurl.substring(lastIndexOf);

            String savePath = sdcard + savename;

            return savePath;

            

        }


        // 創(chuàng)建一個適配器的類

        class MyAdapater extends BaseAdapter {

        private ImgAsy asy;

        

        // 獲得行數(shù)

        @Override

        public int getCount()

         {

            return 15;

           }

        

        @Override

        public Object getItem(int position) {

        return null;

        }

        

        @Override

        public long getItemId(int position)

         {

            return 0;

           }


    @Override

    // 得到每一行控件的樣式和內(nèi)容,則對每一行的控件的內(nèi)容和樣式的修改都在這里進(jìn)行

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

     {

    View view = null;

    ViewHolder holder = null;

    // 繼續(xù)優(yōu)化,優(yōu)化1復(fù)用布局,防止重復(fù)下載,浪費(fèi)不必要的流量

    if (convertView == null)     // convertView:消失的行布局

    {

                    // 找到XML文件轉(zhuǎn)換器

     LayoutInflater inflater = getLayoutInflater();

                    // 把每一行的樣式轉(zhuǎn)換成VIEW對象

      view = inflater.inflate(R.layout.listview, null);

                    // 優(yōu)化2,減少控件的查找.封裝一個類包含所有的控件

       holder = new ViewHolder();

       holder.iv = (ImageView) view.findViewById(R.id.p_w_picpathView1);

       holder.btn = (Button) view.findViewById(R.id.button1);

       holder.tv = (TextView) view.findViewById(R.id.textView1);                       holder.pb = (ProgressBar)view.findViewById(R.id.progressBar1);

       view.setTag(holder);

       } else


     {

       view = convertView;

       holder = (ViewHolder) view.getTag();// 優(yōu)化2

       }

/** 問題:ListView某一行下載完成之后,上下滑動ListView,還未下載的行數(shù)顯示圖片

       原因:復(fù)用造成

       解決:還未下載完成的行數(shù),設(shè)置默認(rèn)圖片顯示*/

// 把沒有參與下載的行的圖片設(shè)置為默認(rèn)圖片,解決未下載的圖片提前顯示出來的問題

   holder.iv.setImageResource(R.drawable.ic_launcher);

// 這兩行代碼是為了判斷當(dāng)前行圖片是否下載完成和異步任務(wù)是否開啟而寫的

     Bitmap bitmap = imgmap.get(dataList.get(position));

     ImgAsy asy = asymap.get(dataList.get(position));

     if (bitmap == null) 

               {

// 圖片尚未下載,判斷當(dāng)前行的異步任務(wù)是否開始

    if (asy == null) 

               {          // 這是一個構(gòu)造方法

    asy = new ImgAsy(holder.iv, position);

                         

    asy.execute(dataList.get(position));

    asymap.put(dataList.get(position), asy);

    }

    // 解決上下滑動過程中,ImageView對象創(chuàng)建了,卻沒有創(chuàng)建新的異步任務(wù)的問題。

    asy.changView(holder.iv);

    } else {

    holder.iv.setImageBitmap(bitmap);

    }

    //根據(jù)下載狀態(tài)設(shè)置各控件的顯示狀態(tài)

    Boolean state=stateMap.get(position);

    if (state==null)

    {

             holder.btn.setEnabled(true);

             holder.pb.setProgress(0);

             holder.tv.setText("未下載");

             holder.btn.setText("下載");

    }else

    {  if (state==true) 

      {

     holder.btn.setEnabled(false);

                 holder.pb.setProgress(100);

                 holder.tv.setText("下載完成");

                 holder.btn.setText("下載完成");

      }else 

          {

               holder.btn.setEnabled(false);

                 holder.tv.setText("下載中");

                 holder.btn.setText("下載中");

          }

    

    }


    final ProgressBar pb = holder.pb;

    final TextView tv = holder.tv;

    final Button btn = holder.btn;

    //用匿名內(nèi)部類的方法寫按鈕的監(jiān)聽事件

    holder.btn.setOnClickListener(new OnClickListener()

 {

    public void onClick(View v) 

    {

    //文件下載異步事件的創(chuàng)建與開啟

    

                  FileAsy fileAsy = new FileAsy(tv, pb, btn, position);

    

                  fileAsy.execute(fileurl.get(position));//帶上了行號。

    }

    });

    return view;

    }

  }

    

    // 下載文件的異步任務(wù)

    class FileAsy extends AsyncTask<String, Integer, String> 

     {

        TextView tv;

        ProgressBar pb;

        Button btn;// 把Button 傳入到下載文件的異步任務(wù)里,為了能夠控制Button的狀態(tài)

        private int position;

        

        public FileAsy(TextView tv, ProgressBar pb, Button btn, int position) {

        super();

        this.tv = tv;

        this.pb = pb;

        this.btn = btn;

        this.position = position;

    }

    

    // 保存路徑

    String savepath = Environment.getExternalStorageDirectory() + "/wenjian.apk";

    private String result;

    

    // 執(zhí)行在doInBackgound之前

    @Override

    protected void onPreExecute()

     {

          btn.setEnabled(false);

          btn.setText("下載");

          stateMap.put(position, false);//文件每一行的下載狀態(tài)

          super.onPreExecute();

      }

    

    @SuppressWarnings("resource")

    @Override

    protected String doInBackground(String... params)

    {

    try {

    URL url = new URL(params[0]);

    // 打開鏈接

    URLConnection connection = url.openConnection();

      int length = connection.getContentLength();

        InputStream is = connection.getInputStream();

          // File file = new File(savepath);

    String savePath3 = getSavePath(params[0]);

      FileOutputStream fos = new FileOutputStream(savePath3);

       byte[] buffer = new byte[1024];

        int len = 0;

          int dllength = 0;// 要寫在這里

    while (-1 != (len = is.read(buffer)))// 先讀取數(shù)據(jù)

    {

    fos.write(buffer, 0, len);// 在寫出數(shù)據(jù)

            // 推送進(jìn)度

    dllength += len;

    publishProgress(dllength * 100 / length);

    }

    } catch (MalformedURLException e) {

    e.printStackTrace();

    } catch (IOException e) {

    result = "下載失敗";

    e.printStackTrace();

    }

    result = "下載成功";

    return result;

    }

    

    protected void onProgressUpdate(Integer... values) {

    

    //該判斷語句為了解決BUG:文件在下載過程中,緩慢上下滑動LiseView,沒有點(diǎn)下載的行出現(xiàn)了對應(yīng)的下載的狀態(tài)。

               //只要Button當(dāng)前行去

    if (isVisiablePositon(listView, position)) {

    pb.setProgress(values[0]);

    tv.setText("已下載" + values[0] + "%");

    }

    super.onProgressUpdate(values);

    }

    

    // 下載完成后,根據(jù)位圖去更新圖片

    protected void onPostExecute(String result)

      {

        Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();

        if (isVisiablePositon(listView, position)) 

         {

            btn.setEnabled(true);

            btn.setText("下載完成");

        }

        stateMap.put(position, true);

        super.onPostExecute(result);

      }

    }

    

    // 下載圖片

    class ImgAsy extends AsyncTask<String, Void, Bitmap> 

     {

        private Bitmap bitmap;

        private ImageView iv;

        private int position;// 加入一個行號的參數(shù)

        

        public ImgAsy(ImageView iv, int position) {

        super();

        this.iv = iv;

        this.position = position;

    }

    

/**

* 問題:下載過程中,上下滑動ListView,等待下載完成,有些行的圖片不顯示

        原因:上下滑動ListView,創(chuàng)建新的ImageView對象,沒有創(chuàng)建新的 AsyncTask

        解決:   1.寫一個方法重新給AsyncTask中的ImageView賦值 

* 通知AsyncTask更新ImageView對象   

* 2.在getView()中調(diào)用

*/

    public void changView(ImageView iv) {

    this.iv = iv;

    }

    

    @Override

    protected Bitmap doInBackground(String... params) {

    try {

    URL url = new URL(params[0]);

    InputStream is = url.openStream();// 開流

    bitmap = BitmapFactory.decodeStream(is);// 下載位圖

    } catch (MalformedURLException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    } catch (IOException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    return bitmap;// 相當(dāng)于handlermessage

    }


// 下載完成后,根據(jù)位圖去更新圖片(寫在內(nèi)部類里)

    protected void onPostExecute(Bitmap bitmap) {

    isVisiablePositon(listView, position);

    if (isVisiablePositon(listView, position)) {

    iv.setImageBitmap(bitmap);

    }

    imgmap.put(dataList.get(position), bitmap);// 保存

    super.onPostExecute(bitmap);

    }

    }


// 寫一個方法判斷當(dāng)前行是否可見。讓數(shù)據(jù)更新只在當(dāng)前行進(jìn)行。返回值是Boolean類型

public Boolean isVisiablePositon(ListView listView, int position) {

    // 獲得可見行第一行行號

    int fp = listView.getFirstVisiblePosition();

    // 獲得可見行最后一行行號

    int lp = listView.getLastVisiblePosition();

    // 在構(gòu)造方法里面去添加position

    // 判斷當(dāng)前行是否在可見范圍

    if (position >= fp && position <= lp) {// 讓可見行去更新控件

      // iv.setImageBitmap(bitmap);

    return true;//返回真,結(jié)束方法

    }

    return false;

    }

    

    // 優(yōu)化2,減少控件的查找.封裝一個類包含所有的控件

    class ViewHolder {

    ImageView iv;

    Button btn;

    TextView tv;

    ProgressBar pb;

    }

    }



向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI