0

I'm doing some background processing in my activity and have a ListView that shows the progress. I 'update' the listView with

adapter.notifyDataSetChanged(); 

However when I leave the activity and then come back, the background processes are still running, but the list view isn't updated. This is presumably because it's a new object, not the previous one. How do I maintain my list view object between activity loads?

This is my activity. I think the issue is that the 'adapter' variable that the download uses to bind to to show updates, is recreated in the onCreate method of the activity, and the 'adapter' variable that the download originally bound to is not in the activity anymore.

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;


import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.model.ProgressEvent;
import com.amazonaws.services.s3.model.ProgressListener;
import com.amazonaws.services.s3.transfer.TransferManager;

//import com.amazonaws.auth.AWSCredentials;
//import com.amazonaws.auth.BasicAWSCredentials;


public class VideosActivity extends Activity {

    ListView           video_list;             
    CustomList         adapter;
    File               storage_dir;
    SharedPreferences  completed_downloads;      //http://developer.android.com/guide/topics/data/data-storage.html
    SharedPreferences  downloaded_data;          //maps position to percent downloaded
    SharedPreferences  queue;                    //holds which fiiles are awaiting download
    String             images[];                 //holds references to all thumnails for vids

    String             volume;                   //something like vol1 or vol2
    String             s3_dir;                   //the directory after the boucket that the files are stored in (do not add first slash)
    String             s3_bucket                 = "com--apps";
    Handler            handler                   = new Handler(); //'tunnel' through whci other threads communicate with main thread


    Map<String, String[][]> video_config         = new HashMap<String, String[][]>(); //holds info about video thumbs and filenames for all apps
    ArrayList<String>       arr_videos           = new ArrayList<String>();  //holds video names
    DownloadQueue           queue_manager        = new DownloadQueue();



    @Override
    public void onCreate(Bundle savedInstanceState) {

        Log.v("dev", "onCreateCalled");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        volume               = getPackageName().split("\\.")[2]; //something like vol1 or vol2
        s3_dir               = "android/" + volume + "/"; //the directory after the boucket that the files are stored in (do not add first slash)
        completed_downloads  = getSharedPreferences("completed_downloads", 0); 
        downloaded_data      = getSharedPreferences("downloaded_data", 0); 
        queue                = getSharedPreferences("queue", 0); 
        storage_dir          = getApplicationContext().getExternalFilesDir(null);        //private to app, removed with uninstall
        adapter              = new CustomList(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_video_data();                       //store vid dat in array

        ensure_connection_or_warn();
    }

    public boolean ensure_connection_or_warn()
    {
        if(have_connection())
        {
          return true;
        }
        else
        {
          Toast.makeText(this, "No Internet connection", Toast.LENGTH_LONG).show();
          return false;
        }
    }
    protected void ensureStorageDirExists( File dir ) 
    {
      if (!dir.exists())
      {
        dir.mkdirs();
      }
    }

    public void set_video_data() 
    {


      config_video_data(); //run config

      images     = video_config.get(getPackageName())[0]; //set images

      for (String name : video_config.get(getPackageName())[1] ) { //set video info, this should be streamlined but is due to legacy code and my crap Java skills, consider doing like this: http://developer.android.com/guide/topics/resources/more-resources.html#TypedArray
        arr_videos.add(name);
      }

    }


    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())
      {
        Log.v("dev", "have internet connection");
        return true;
      }
      else
      {
        Log.v("dev", "No internet connection");
        return false;
      }

    }





    public class DownloadQueue
    {
      protected void process()
      {
        if (queue.size() > 0 && queue.get(0).download_status == "queued") //this is meant to force one download at a time
        {
          queue.get(0).start();
          adapter.notifyDataSetChanged();
        }
      }
      protected void add(Integer position)
      {
        queue.edit.putInt(position+"");
        d.download_status = "queued";
        adapter.notifyDataSetChanged();
      }
      protected boolean position_is_queued(Integer position)
      {
        for (Download d : queue ) {
          if(d.position == position)
          {
            return true;
          }
        }

        return false;
      }
      protected void remove(Download d)
      {
        queue.remove(d);
        adapter.notifyDataSetChanged();
      }
    }

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

        public CustomList(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( 
            getResources().getIdentifier(images[position], "drawable", getPackageName())
          );

          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 completed_downloads.getBoolean(position + "", false);
        }

        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 if( downloaded_data.contains(position+"") )  //it it's currently being downloaded
          {
            btn.setText(downloaded_data.getInt(position+"", 0) + "%");
            btn.setEnabled(false);
          }
          else if( queue_manager.position_is_queued(position) ) //it's in the queue
          {
            btn.setText("Queued");
            btn.setEnabled(false);
          }
          else
          {
            btn.setText("Download");
            btn.setEnabled(true);

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

                queue_manager.add(position);
              }
            });
          }
        }

    }


    public class Download
    {

       File              new_video_file;
       int               position;
       String            download_status;
       com.amazonaws.services.s3.transfer.Download  download;

       protected void queue(int position) 
       {
          this.position                = position;
          queue_manager.add(this);
          queue_manager.process();

          //put this download in the queue
          //start downloading if it's the only one in the queue
       }
       protected void start() 
       {
          if(!ensure_connection_or_warn())
          {
            return;
          }

          this.download_status         = "started";
          this.new_video_file          = new File(storage_dir, arr_videos.get(position));                   //local file to be writtent to
          TransferManager tx           = new TransferManager(credentials);
          //http://stackoverflow.com/questions/6976317/android-http-connection-exception
          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()
       {
          this.download_status         = "downloading";
          Double progress = this.download.getProgress().getPercentTransfered();
          Integer percent  = progress.intValue();
          //Log.v("runnable", percent + "");

          downloaded_data.edit().putInt(position+"", percent).commit();


          adapter.notifyDataSetChanged();
       }
       protected void onComplete()
       {
          Log.v("dev", "download complete!!!");
          //downloaded_data.remove(position);

          this.download_status         = "complete";

          completed_downloads.edit().putBoolean(position + "", true).commit();

          queue_manager.remove(this);
          queue_manager.process();

          adapter.notifyDataSetChanged();


         // this.download.abort();
       }
    }


}
pixelearth
  • 13,674
  • 10
  • 62
  • 110

1 Answers1

0

Not exactly sure what happens during background processing and what do you mean by ListView state, but my suggestion would be:

try the following:

@Override
protected void onResume() {
    super.onResume();

    yourAdapter.clear();
    yourAdapter.addAll(yourData);  // API level [1..10] use for(..){ yourAdapter.add(yourData.get(index)) }
    yourAdapter.notifyDataSetChanged();
}

Reason:

An adapter keeps a copy of all the elements, so when you call notifyDataSetChanged, it checks its own copy of the elements

Boris Mocialov
  • 3,439
  • 2
  • 28
  • 55
  • This won't solve my problem since the previous BG process binds to a different adapter object in it's progress callback... I've updated the code above, but I fear it's too dense to be of any use. – pixelearth Aug 08 '13 at 02:08