Loop to upload list images one by one
I want to upload multiple images one by one, like once user do tap on upload all button, it has to start with first image visible in a list, once first image will be uploaded to server then automatically has to start second for upload but after one or two second interval and same for all available images in a list.
This is my code, which allow me to upload single image:-
Code to upload single image
// btnUpload
holder.uploadImageButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Upload
startUpload(position);
}
});
I am using below code, but its uploading/syncing all images at same time, my mean together, like i have 500 images in a list so its uploading all 500 together and as a result i am getting error when internet connection goes down and many times not getting accurate status of uploaded images !
private SparseBooleanArray flags = new SparseBooleanArray();
// At onClick, set all the flags to indicate that some data needs to be synced
ImageButton buttonUploadAll = (ImageButton) findViewById(R.id.sync_btn);
buttonUploadAll.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
for(int position=0; position<listView.getAdapter().getCount(); position++)
{
flags.put(position, true);
}
// Calling this would ensure a call to getView() on every
// visible child of the listview. That is where we will check if
// the data is to be synced and displayed or not
((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
}
});
@Override
// In getView of the listview's adapter
public View getView(int position, View convertView, ViewGroup parent) {
// If this item is to be synced
if(flags.get(position)) {
startUpload();
// Mark as synced
flags.put(position, false);
}
// Rest of the method that draws the view....
}
that's why i want to upload multiple images one by one (in a queue manner)
Solution 1:
I have tried to write a service which will upload image from shared pref one by one : Note : i hv hardcoded some of things here like image are from sdcard so path is hardcoded, images names are hardcoded, so plz change it appropriately and try out below code , i hv tested and worked for me
Below code contains Service, Activity[upload button, listview], xmlLayout, php service which will upload image on ftp.
Activity :
public class MainActivity extends Activity {
SharedPreferences sharedPref;
SharedPreferences.Editor editor;
ListView listview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sharedPref = getSharedPreferences("myfiles", MODE_PRIVATE);
editor = sharedPref.edit();
editor.putString("0", "monika_pin.png");
editor.putString("1", "monika_pin1.png");
editor.putString("2", "monika_pin2.png");
editor.commit();
String[] arr = new String[] { "/mnt/sdcard/monika_pin.png",
"/mnt/sdcard/monika_pin1.png", "/mnt/sdcard/monika_pin2.png" };
List<String> list = Arrays.asList(arr);
MyAdapter adapter = new MyAdapter(this, R.layout.listitem_imv, list);
listview = (ListView) findViewById(R.id.listView1);
listview.setAdapter(adapter);
}
class MyAdapter extends ArrayAdapter<String> {
List<String> mList;
LayoutInflater mInflater;
int mResource;
public MyAdapter(Context context, int resource, List<String> objects) {
super(context, resource, objects);
mResource = resource;
mInflater = getLayoutInflater();
mList = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(mResource, null);
} else {
view = convertView;
}
ImageView imageView = (ImageView) view
.findViewById(R.id.imageView1);
TextView textView = (TextView) view.findViewById(R.id.textView1);
imageView.setTag(mList.get(position));// tag of imageView == path to
// image
new LoadImage(imageView).execute();
textView.setText(mList.get(position).toString());
return view;
}
}
class LoadImage extends AsyncTask<Object, Void, Bitmap> {
private ImageView imv;
private String path;
public LoadImage(ImageView imv) {
this.imv = imv;
this.path = imv.getTag().toString();
}
@Override
protected Bitmap doInBackground(Object... params) {
Bitmap bitmap = null;
// File file = new File(
// Environment.getExternalStorageDirectory().getAbsolutePath() +
// path);
File file = new File(path);
if (file.exists()) {
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
if (!imv.getTag().toString().equals(path)) {
/*
* The path is not same. This means that this image view is
* handled by some other async task. We don't do anything and
* return.
*/
return;
}
if (result != null && imv != null) {
imv.setVisibility(View.VISIBLE);
imv.setImageBitmap(result);
} else {
imv.setVisibility(View.GONE);
}
}
}
public void buttonClick(View view) {
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
}
Service :
public class MyService extends Service {
SharedPreferences sharedPref;
SharedPreferences.Editor editor;
int serverResponseCode = 0;
String upLoadServerUri = null;
private static final String TAG = "com.example.ServiceExample";
@Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
sharedPref = getSharedPreferences("myfiles", MODE_PRIVATE);
/************* Php script path ****************/
upLoadServerUri = "http://myserver/uploadimage.php";
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand " + startId);
final int currentId = startId;
Runnable r = new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
// long endTime = System.currentTimeMillis() + 10*1000;
// while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
uploadFile(sharedPref.getString(i + "", ""));
} catch (Exception e) {
}
}
// }
Log.i(TAG, "Service running " + currentId);
}
stopSelf();
}
};
Thread t = new Thread(r);
t.start();
return Service.START_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
Log.i(TAG, "Service onBind");
return null;
}
@Override
public void onDestroy() {
Log.i(TAG, "Service onDestroy");
}
public int uploadFile(String sourceFileUri) {
String fileName = sourceFileUri;
HttpURLConnection conn = null;
DataOutputStream dos = null;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1 * 1024 * 1024;
// File sourceFile = new
// File(Environment.getExternalStorageDirectory(),sourceFileUri);
File sourceFile = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/" + fileName);
if (!sourceFile.isFile()) {
return 0;
} else {
try {
// open a URL connection to the Servlet
FileInputStream fileInputStream = new FileInputStream(
sourceFile);
URL url = new URL(upLoadServerUri);
// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true); // Allow Inputs
conn.setDoOutput(true); // Allow Outputs
conn.setUseCaches(false); // Don't use a Cached Copy
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("uploaded_file", fileName);
dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
// dos.writeBytes("Content-Disposition: form-data; name="uploaded_file";filename=""+ fileName + """
// + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\";filename=\""
+ fileName + "\"" + lineEnd);
dos.writeBytes(lineEnd);
// create a buffer of maximum size
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
serverResponseCode = conn.getResponseCode();
String serverResponseMessage = conn.getResponseMessage();
Log.i("uploadFile", "HTTP Response is : "
+ serverResponseMessage + ": " + serverResponseCode);
if (serverResponseCode == 200) {
}
// close the streams //
fileInputStream.close();
dos.flush();
dos.close();
} catch (MalformedURLException ex) {
ex.printStackTrace();
Log.e("Upload file to server", "error: " + ex.getMessage(), ex);
} catch (Exception e) {
e.printStackTrace();
Log.e("Upload file to server Exception",
"Exception : " + e.getMessage(), e);
}
return serverResponseCode;
} // End else block
}
}
XmlLayout :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.service.MainActivity" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:onClick="buttonClick"
android:text="Button" />
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/button1"
android:layout_centerHorizontal="true" >
</ListView>
</RelativeLayout>
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.service"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
>
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService" />
</application>
</manifest>
PhP Script :
<?php
$file_path = "uploads/";
$file_path = $file_path . basename( $_FILES['uploaded_file']['name']);
if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $file_path)) {
echo "success";
} else{
echo "fail";
}
?>
Note : Above sure where u create this php file on ftp, create a folder also called upload where all files will be uploaded
If u wish to download complete Source code --> Source Code
Solution 2:
- don't forget to close the connection after you are done writing bytes
conn.close()
- you don't need to use any
Runnables
/Threads
1) add the following interface to your AsyncTask
:
public interface onImageUploadListener{
void onImageUploaded(String status);
}
2) Declare its instance as a class field in your AsyncTask
(I called it listener) and add the following constructor:
public UploadFileAsync(onImageUploadListener listener){
this.listener = listener;
}
3) Use AsyncTask.THREAD_POOL_EXECUTOR
if you are on API >11 to prevent your upload task from blocking other tasks you might be running.
4) Let your Adapter
class (for god's sake, remove the Runnable
part first) implement the interface:
public class ImageAdapter extends BaseAdapter implements UploadFileAsync.onImageUploadListener
you will need to implement the onImageUploaded(String status)
method:
@Override
public void onImageUploaded(String status){
//here you are getting your server response)
//I use a bit of pseudo-code to describe this condition
if(position < lastPosition){
new UploadFileAsync(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, String.valueOf(nextPosition));
}else{
//we are done
}}
5) In your AsyncTask, assign the value of server response to some String and do the following on your onPostExecute()
method:
listener.onImageUploaded(yourResponseCode);
6) To force a 1-second delay, just call Thread.sleep(1000);
inside your doInBackground()
method just before the return statement.
The onImageUploaded()
callback will be triggered each time your AsyncTask
finishes, and you can execute it again and again from this method until you are done with upload. You can also add more checks to this method, for example check for error codes but this is up to you.
Hope this helps. Cheers
Solution 3:
First create a class like ImageSyncService
posted here. Many components of this class are missing as I extracted it from my ongoing project, but you'll get the overview. If something is not clear you can ask me.
public class ImageSyncService extends IntentService {
private static final String TAG = "ImageSyncService";
private Image image;
private ImageOpenHelper imageOpenHelper;
private SharedPreferences preferences;
public ImageSyncService() {
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
Logger.d(TAG, "onHandleIntent");
imageOpenHelper = new ImageOpenHelper(getApplicationContext());
preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
image = (Image) intent.getSerializableExtra(Config.REQUEST_EXTRA_OBJECT);
if(image == null)
return;
if(image.getResourceURI() == null) {
image.setSyncStatus(SyncStatus.SYNCING);
imageOpenHelper.updateImage(image, false);
Response response = MultiPartDataServer.postData(Config.URL_IMAGE_UPLOAD, nameValuePairs, null);
/* on success:
*
* image.setSyncStatus(SyncStatus.SYNCED);
* imageOpenHelper.updateImage(image, false);
*
* */
}
}
On uploadAll
button click do this:
ArrayList<Image> images = imageOpenHelper.getUnsyncedImages(SyncStatus.TO_BE_UPLOADED);
Intent imageSyncService = null;
for(Image i: images) {
imageSyncService = new Intent(getApplicationContext(), ImageSyncService.class);
imageSyncService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
imageSyncService.putExtra(Config.REQUEST_EXTRA_OBJECT, i);
startService(imageSyncService);
}
Hope this helps :)