0

我有一个错误,我认为是由于列出重用对象的方式。我有一个下载按钮列表,下载时会显示进度读数。更新代码在后台线程中。

当我滚动列表时,显示进度的按钮会跳转到其他列表元素。我怎样才能阻止这个?很难想象,所以我做了一个视频:

http://www.youtube.com/watch?v=EiT2YWb2Prs&feature=youtu.be

顺便说一句,该视频是由我的客户制作的,因此请忽略“三星错误”位。我是开发者...

这是代码:

公共类 VideosActivity 扩展 Activity {

ListView           video_list;             
CustomList2        adapter;
File               storage_dir;

String             s3_bucket              = "xx";
String             s3_dir                 = "android/vol1/"; //the directory after the boucket that the files are stored in (do not add first slash)
Handler            handler                = new Handler(); //'tunnel' through whci other threads communicate with main thread


ArrayList<String>  arr_videos             = new ArrayList<String>();
ArrayList<String>  arr_sdcardvideos       = new ArrayList<String>();
int                images[]               = {R.drawable.kr115,R.drawable.kr200,R.drawable.kr201,R.drawable.kr202,R.drawable.kr203,R.drawable.kr205,R.drawable.kr206,R.drawable.kr207,R.drawable.kr208,R.drawable.kr209,R.drawable.kr210,R.drawable.kr211,R.drawable.kr212,R.drawable.kr213,R.drawable.kr213,R.drawable.kr214,R.drawable.kr215,R.drawable.kr216,R.drawable.kr210,R.drawable.kr211,R.drawable.kr212,R.drawable.kr213};

@Override
public void onCreate(Bundle savedInstanceState) {

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


    storage_dir    = getApplicationContext().getExternalFilesDir(null);        //private to app, removed with uninstall
    adapter        = new CustomList2(this, R.layout.customlist, arr_videos);
    video_list     = (ListView)findViewById(R.id.list);

    video_list.setAdapter(adapter);         //set adapter that specifies list contents
    ensureStorageDirExists( storage_dir );  //make sure storage dir exists
    set_sdcard_video_data();                //store vids arleady on card
    set_video_data();                       //store vid dat in array

    if(!have_connection())
    {
      Toast.makeText(this, "No Internet connection", Toast.LENGTH_LONG).show();
      return;
    }

}
protected void ensureStorageDirExists( File dir ) 
{
  if (!dir.exists())
  {
    dir.mkdirs();
  }
}

public void set_sdcard_video_data() 
{
    arr_sdcardvideos.clear();

    for(File f:storage_dir.listFiles())
    {
      arr_sdcardvideos.add( f.getName() );
    }
}


public void set_video_data() 
{
    arr_videos.add("02Posture_and_Walk.m4v");
    arr_videos.add("03Embrace_Connection_and_Musicality.m4v");
    arr_videos.add("04Left_Turning_Check_Step.m4v");
    arr_videos.add("05Basic_Right_Turn.m4v");
    arr_videos.add("06Ocho_Cortado.m4v");
    arr_videos.add("07Media_Vuelta.m4v");
    arr_videos.add("08The_Cross.m4v");
    arr_videos.add("09Front_Ochos.m4v");
    arr_videos.add("10The_Cross_in_Cross_System.m4v");
    arr_videos.add("11Back_Ochos.m4v");
    arr_videos.add("12Molinete_Giro.m4v");
    arr_videos.add("13Right_Turn.m4v");
    arr_videos.add("14Combining_All_the_Elements_1.m4v");
    arr_videos.add("15Combining_All_the_Elements_2.m4v");
    arr_videos.add("16Combining_All_the_Elements_3.m4v");
    arr_videos.add("17Combining_All_the_Elements_4.m4v");
    arr_videos.add("18Combining_All_the_Elements_5.m4v");
    arr_videos.add("19Combining_All_the_Elements_6.m4v");
    arr_videos.add("20Demo_Using_All_the_Elements.m4v");
    arr_videos.add("36Etiquette.m4v");
}

public SharedPreferences stored_vals()
{

    return PreferenceManager.getDefaultSharedPreferences(this);
}

public boolean have_connection()
{
  ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

  if(cm.getActiveNetworkInfo()!=null && cm.getActiveNetworkInfo().isConnected() && cm.getActiveNetworkInfo().isAvailable())
  {
    return true;
  }
  else
  {
    return false;
  }

}



public void download_video(int position, View btn)
{
}




public class CustomList2 extends ArrayAdapter<String>
{
    View view;
    int position;
    Button btn;

    public CustomList2(Context context, int layout_id, ArrayList<String> objects) 
    {
        super(context, layout_id, objects);
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup view_group) 
    {
      set_view(convertView);

      this.position          = position;
      TextView  text_view    = (TextView) view.findViewById(R.id.name);
      ImageView image        = (ImageView) view.findViewById(R.id.img);
      btn                    = (Button) view.findViewById(R.id.play);

      prepare_btn();

      text_view.setText( list_text() );
      image.setImageResource(images[position]);

      return view;
    }

    public String list_text()
    {
      String s = arr_videos.get( position ).replace("_", " ").replace(".m4v", "");
      s        = s.substring(2, s.length());
      return s;
    }

    public void set_view(View convertView)
    {
      if(convertView == null) 
      {
        LayoutInflater inflater                      = getLayoutInflater();
        view                                         = inflater.inflate(R.layout.customlist, null);
      } 
      else 
      {
        view = convertView;
      }
    }

    public Boolean is_downloaded()
    {
      return arr_sdcardvideos.contains(arr_videos.get(position));
    }

    public void prepare_btn()
    {
      btn.setTag((Integer) position);

      if(is_downloaded() == true)
      {
        btn.setText("Play ");
        btn.setEnabled(true);

        btn.setOnClickListener( new OnClickListener() 
        {
          public void onClick(View btn) 
          {
            int    position   = (Integer) btn.getTag();
            Intent i          = new Intent(VideosActivity.this, PlayVideoActivity.class);
            String video_path = storage_dir + "/" + arr_videos.get(position);

            Log.v("video_path", video_path);

            i.putExtra("video_path", video_path);
            startActivity(i);
          }
        });
      }
      else
      {
        btn.setText("Download ");

        btn.setOnClickListener( new OnClickListener() 
        {
          public void onClick(View btn) 
          {
            int position = (Integer) btn.getTag();
            btn.setEnabled(false);
            //download_video( position, btn );

            Download d   = new Download();

            d.start(position, (Button) btn);
          }
        });
      }
    }

}




public class Download
{

   File              new_video_file;
   Button            btn;              //the progress meter needs to know what button called this. set via setter method below.
   int               position;
   com.amazonaws.services.s3.transfer.Download  download;

   protected void start(int position, Button btn) 
   {
      this.btn                     = (Button) btn;
      this.position                = position;
      this.new_video_file          = new File(storage_dir, arr_videos.get(position));                   //local file to be writtent to
      AWSCredentials credentials   = new BasicAWSCredentials("xx", "xx" );
      TransferManager tx           = new TransferManager(credentials);
      this.download                = tx.download(s3_bucket, s3_dir + arr_videos.get(position), new_video_file);

      download.addProgressListener(new ProgressListener() 
      {
        public void progressChanged(final ProgressEvent pe) 
        {
          handler.post( new Runnable() 
          {
            @Override
            public void run() 
            {
              if ( pe.getEventCode() == ProgressEvent.COMPLETED_EVENT_CODE )
              {
                Download.this.onComplete();
              }
              else
              {
                Download.this.onProgressUpdate();
              }
            }
          });
        }
      });
   }

   //protected void onProgressUpdate(Double progress)
   protected void onProgressUpdate()
   {
      Double progress = this.download.getProgress().getPercentTransfered();
      String percent  = progress.intValue() + "%";
      Log.v("runnable", percent);

      btn.setText(percent);
      Log.v("dev", progress + "");
   }
   protected void onComplete()
   {
      Log.v("dev", "download complete!!!");
      set_sdcard_video_data();
      adapter.notifyDataSetChanged();
     // this.download.abort();
   }
}

}

4

1 回答 1

0

您的下载线程保留对按钮的引用。当您滚动时,按钮会被重复用于不同的列表元素。您需要找到一种方法来以某种方式更新 Thread 中的 Button。当列表元素不可见时,Thread 中的 Button 也可以为 null。

编辑:

真的没那么复杂。首先:你应该使用ViewHolder,这会让你的生活更轻松。然后你可以做这样的事情

@Override
public View getView(final int position, View convertView, ViewGroup view_group) {
    View view = null;
    ViewHolder holder = null;

    if(convertView == null){
        view = {inflate view}
        view.setTag(holder = new ViewHolder());
        holder.view1 = view.findViewById(...);
        {get rest of the views}
    }else{
        view = convertView;
        holder = (ViewHolder)view.getTag();
    }

    if(holder.getDownloadThread() != null){
        holder.getDownloadThread().setButton(null);
    }

    ...
}

你明白了。

于 2013-05-06T23:23:24.627 回答