I'm having difficulties keeping track of my queue and uploading them at a later moment.
The upload image is a asynctask and in the postexecute a mail is going out to send the uploaded picture.
This is my UploadImage AsyncTask. I think i'm doing way too difficult and that it can be done much easier than it is right now.
private class UploadImageTask extends AsyncTask<Void, Void, Integer> {
ProgressDialog dialog;
/**
* Private integer which counts how many times we've tried to upload the
* Image.
*/
private int _counter = 0;
private List<String> imageUploadList = new ArrayList<String>();
#Override
protected void onPreExecute() {
super.onPreExecute();
if(AppStatus.haveNetworkConnection(_context)){
if(isPhotoTaken()){
dialog = new ProgressDialog(Step4.this);
dialog.setCancelable(false);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage(getString(R.string.uploadingMessage));
dialog.setTitle(getString(R.string.uploadingTitle));
dialog.show();
}
}
}
protected Integer doInBackground(Void... params) {
init();
postData();
return null;
}
public void init(){
_counter = 0;
_beenHere = true;
for(String path : imageUploadList){
Debug.out("Path: "+path);
}
}
public void postData() {
if (isPhotoTaken()) {
if(AppStatus.haveNetworkConnection(_context)){
if(_beenHere){
ImageUploader.uploadFile(getPhotoPath(),
"http://obo.nl/android-upload-image.php", Step4.this);
} else {
for(String path : imageUploadList){
Debug.out(path);
ImageUploader.uploadFile(path,
"http://obo.nl/android-upload-image.php", Step4.this);
}
}
} else {
if (_counter == 0) {
_counter++;
_activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(_context,
getString(R.string.noInternetImageNotUploaded),
Toast.LENGTH_LONG).show();
}
});
imageUploadList.add(getPhotoPath());
}
try {
if(_beenHere){
_beenHere = false;
goToNextIntent();
}
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
postData();
}
}
}
private void goToNextIntent(){
Intent intent = new Intent(Step4.this, Step5.class);
intent.putExtra(EXTRA_MESSAGE, (Serializable) _user);
intent.putExtra(EXTRA_MESSAGE2, _isRepairable);
intent.putExtra(EXTRA_MESSAGE3, _injury);
intent.putExtra(EXTRA_MESSAGE4, _category);
intent.putExtra(EXTRA_MESSAGE5, _inch);
intent.putExtra(EXTRA_MESSAGE6, _size);
startActivity(intent);
}
protected void onPostExecute(Integer result) {
if(isPhotoTaken()){
if(dialog != null){
dialog.dismiss();
}
}
mailing(_isRepairable);
new MyAsyncTask().execute(_mail);
}
}
The line:
if(AppStatus.haveNetworkConnection(_context))
returns a boolean true if the user has a working internet connection. false otherwise.
What I want is to queue all the image paths (and mails sent afterwards) in the desired ArrayList so i can send them all at a later moment when the user has a working internet Connection. Please help me out!
You could store your image paths in a list (or something similar) and persist the list, let's say in Shared Preferences. As you finish uploading a picture, you will remove it from that list and continue to the next one, and so on until your list is empty.
While uploading, if the internet connection drops it will not affect you, you will always have persisted the list of images that are still to be uploaded.
Register a broadcast receiver to listen for wi-fi connection, when it gets connected it could automatically continue the upload - this is just a suggestion.
Related
I am creating an app where user can upload images, I am uploading images one after another using retrofit. Right now I am running a for loop for it, but it is not a good way to do it. I cannot use service because I need progress dialog as well on main screen to let user know upload is happening. Is there a way to maintain some kind of queue to handle this?
You can use the AsyncTask and Retrofit to do it it can be done with the retrofit alone but as I have already done it with AsyncTask have a look.
public class AsyncBulkUpload extends AsyncTask<Boolean, Integer, Boolean> {
private ApiInterface mApiInterface;
private Call<ResponseBody> mResponseBodyCall;
private Response<ResponseBody> mResponseBody;
private RequestBody mRequestBody;
private Service mService;
private Bitmap mItemBitmap;
public int mTotalCount = 0;
public AsyncBulkUpload(Service service) {
mService=service;
mApiInterface = ApiClient.getClient(mService.getApplicationContext()).create(ApiInterface.class);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mTotalCount = sClosetList.size();
//Show you dialog
}
#Override
protected Boolean doInBackground(Boolean... itsRetry) {
/**
*Check if its retry or not
* if yes don't get the placeholder ids.
* or else hit and get place holder ids
*/
//Run your loop here.
return upload();
}
private Boolean upload() {
if (isCancelled())
return false;
if (sClosetList.size() > 0) {
//Item image
try {
mItemBitmap = Glide.with(mService.getApplicationContext())
.load(sClosetList.get(0).mItemImage)
.asBitmap()
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
} catch (InterruptedException e) {
//Coudnt get the image so cant go further
LogPrint.printError("WHILE GETTING BITMPAP");
return false;
} catch (ExecutionException e) {
//Coudnt get the image so cant go further
LogPrint.printError("WHILE GETTING BITMPAP");
return false;
}
FormBody.Builder bodyBuilder = new FormBody.Builder();
bodyBuilder.add("image", mItemBitmap);
/**
*Label image can or can not be available
*/
mRequestBody = bodyBuilder.build();
mResponseBodyCall = mApiInterface.uploadProducts(mRequestBody);
try {
mResponseBody = mResponseBodyCall.execute();
} catch (IOException e) {
e.printStackTrace();
return false;
}
if (!mResponseBody.isSuccessful()) {
/**
*Some server error try again
*/
return false;
}
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//Update your progressbar
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
//Dismiss the dialog
if (aBoolean) {
Toast.makeText(mService, R.string.uploaded_successful, Toast.LENGTH_LONG).show();
}
}
}
I am writing here because this is my last solution of understanding this type of programming.The problem is that I got stuck on what to use to handle the connection to a server and log-in. Should I use async task, handler or thread ? I didn't find a concrete answer stating which one to use, only found that async task is used to download images or other download stuffs.
Until now I have used a thread to connect to the server. The problem I encountered was when I catch the exception ( Putting invalid username/password ) and try to log-in again. ( I needed to "close" the last thread and start one again )
After this I started to use async task but I don't really understand how it should work and I am stuck on a toast of invalid username/password.
private class connectStorage extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
api = DefaultClientFactory.create(host, getUser, getPassword);
if (api.getAuthToken().trim().length() > 3) {
//TO DO LAYOUT CHANGE;
}
} catch (StorageApiException e) {
e.printStackTrace();
Log.i("TEST", "" + e.getMessage());
}
return null;
}
Also, I am 100% sure that calling inflate in the doInBackground method won't work too ( there I wanted to change the activity ).
I am starting the async task on a button press.
When you are using asynctask
You have doInBackground and onPostExecute
So basically get a json or string or boolean as a result from doinbackground
and in onpostexecute check if the login in succesful or not if its succesful save the data from server and start an intent to go to another activity or toast the user that that user login details are wrong and try again.
So your asynctask can be an inner class of your activity class which is login and onClickSubmit button call the asynctask class and on post execute parse the json and according to the result decide what to do
Example:
public class SignInAsycTask extends AsyncTask<RequestParams, Void, String> {
#Override
protected String doInBackground(RequestParams... params) {
return new HttpManager().sendUserData(params[0]);
}
#Override
protected void onPostExecute(String result) {
String[] details = parseJsonObject(result);
if (details != null) {
user.setUser_id(Integer.valueOf(details[0]));
user.setName(details[1]);
if (details.length > 2) {
user.setProfilePic(details[2]);
}
setSharedPreferences();
startActivity(new Intent(Signin.this, MainActivity.class));
finish();
} else {
Toast.makeText(Signin.this, "please try again",
Toast.LENGTH_LONG).show();
}
}
}
public String[] parseJsonObject(String result) {
JSONObject obj = null;
try {
obj = new JSONObject(result);
if (obj.has("success")) {
if (obj.getInt("success") == 1) {
if (obj.has("user_pic")) {
return new String[] {
String.valueOf(obj.getInt("user_id")),
obj.getString("user_name"),
obj.getString("user_pic") };
} else {
return new String[] {
String.valueOf(obj.getInt("user_id")),
obj.getString("user_name"), };
}
} else {
return null;
}
} else {
return null;
}
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
here my RequestParams are just a object where I stored all the details like url parameters to send etc and the output of the doinbackground is a String and I am parsing it in my postexecute method
In my app I performing loading data from web and then displaying it to user. Before loading data app shows progress dialog. I have problem if user locks phone in the middle of loading operation, or server is overloaded and can't respond in time my application freezes, because it doesn't dismiss progress dialog, or in some cases it crashes because lack on needed data.
If some error happened while loading data I want show some dialog to user to let him know about error and ask him should application repeat last request. I tried to use AlertDialog for it, but I haven't succeed.
Here is code of one activity (There is no progress dialog here, but it demonstrates how I loading data):
#EActivity(R.layout.layout_splash)
#RoboGuice
public class SplashScreenActivity extends Activity {
#Inject
private AvtopoiskParserImpl parser;
#Bean
BrandsAndRegionsHolder brandsAndRegionsHolder;
#ViewById(R.id.splash_progress)
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
}
#Background
protected void loadData() {
publishProgress(10);
LinkedHashMap<String, Integer> brands = null;
try {
brands = parser.getBrands();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(50);
LinkedHashMap<String, Integer> regions = null;
try {
regions = parser.getRegions();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(70);
populateData(brands, regions);
}
#UiThread
protected void populateData(LinkedHashMap<String, Integer> brands, LinkedHashMap<String, Integer> regions) {
Intent intent = new Intent(SplashScreenActivity.this, SearchActivity_.class);
brandsAndRegionsHolder.brandsMap = brands;
brandsAndRegionsHolder.regionsMap = regions;
publishProgress(100);
startActivity(intent);
finish();
}
#UiThread
void publishProgress(int progress) {
progressBar.setProgress(progress);
}
}
parser.getBrands() and parser.getRegions() are loading data from the web.
I want to do something like this:
boolean repeatRequest = true;
while (repeatRequest) {
try {
brands = parser.getBrands();
repeatRequest = false;
} catch (IOException e) {
Log.e(e.getMessage());
repeatRequest = showErrorDialog();
}
}
But I didn't manage to do so because this code executes in background thread, but dialog should be shown in UI thread.
I believe that it should be standard approach of doing so, but didn't manage to find it.
Any ides how can I implement this?
The best way is to use AsyncTask.
private class LoadDataTask extends AsyncTask<Void, Integer, Object> {
private ProgressDialog mProgress;
protected Object doInBackground(Void... params) {
// This method runs in background
Object result = null;
try {
result = parser.parse();
} catch (Exception e) {
result = e.getMessage();
}
return result;
}
protected void onProgressUpdate(Integer... progress) {
// This method runs in UI thread
mProgress.setProgress(progress[0]);
}
protected void onPreExecute() {
// This method runs in UI thread
mProgress = new ProgressDialog(context);
mProgress.show();
}
protected void onPostExecute(Object result) {
// This method runs in UI thread
mProgress.dismiss();
if (result instance of String) {
// Here you can launch AlertDialog with error message and proposal to retry
showErrorDialog((String) result);
} else {
populateData(result);
}
}
}
webservice.UpdateAllNews();
This function is downloading data from online database to local database.
What i want is i want to launch next activity after detect the function has downloaded finish all the data.
P/S the data is large
This is my current situation
webservice.UpdateAllNews();
int secondsDelayed = 17;
new Handler().postDelayed(new Runnable() {
public void run() {
startActivity(new Intent(Main_Launcher.this,
Main_AllLatestNews.class));
finish();
}
}, secondsDelayed * 1000);
This is another class function
public void UpdateAllNews() {
try {
List<List_CategoryNews> newsCat = dbhelper.getAllNewsCategories();
for (List_CategoryNews nwCat : newsCat) {
int CatNewsID = nwCat.getCatID();
if (CatNewsID != 0) {
dbhelper.DeleteNews(CatNewsID);
GetNews(CatNewsID, datetemp1, datetemp2);
}
String log = " NewsCatID- " + nwCat.getCatID()
+ " category Name- " + nwCat.getNewCatName();
System.out.println(log);
}
} catch (Exception ex) {
AlertDialog.Builder b = new AlertDialog.Builder(mContext);
b.setMessage(ex.toString());
b.show();
}
}
This one is constant launch after 17 seconds, i want auto start activity after finish downloading data from online database instead of delay 17 seconds.
Any suggestion?
Maybe try to use AsyncTask:
private class YourTask extends AsyncTask<String, Void, String>
{
#Override
protected String doInBackground(String... urls)
{
webservice.UpdateAllNews();
}
#Override
protected void onPostExecute(String result)
{
startActivity(new Intent(Main_Launcher.this,Main_AllLatestNews.class));
finish();
}
}
and how to run it:
YourTask task = new YourTask();
task.execute("...");
Why don't you use simple client-server methodology like Observer-Observable?
When the task is done the observable will call update function of the observer which will be your primary activity.
i got a problem getting my AsyncTask to work correct. My App offers the possibility to connect with your Google Account and add and receive tasks by using the Tasks API. When the users wants to synchronize with his account, the doInBackground() method is started. Right before that, a ProgressDialog is displayed in the onPreExecute() method of the AsyncTask class.
If the synchronisation has been successfully executed, the onPostExecute() method 'should' be called fading out the ProgressDialog.
But there is problem: the onPostExecute() ethod is called before the work in the doInBackground() is finished.
In doInBackground() I receive the token used for the authorization:
token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
That's all. But right before that, the onPostExecute() is called and the ProgressDialog disappears while the token is still retrieving. The wired thing is that when I start the app and synchronizes for the first time, it works like it should. But after that the onPostExecute() method finishes before the work is completed. Does this have to do that there are requests to a server while executing
future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
How can I tell the onPostExecute() method that there is still work to do?
private class SynchronizeGoogle extends AsyncTask<Void, Integer, Void>
{
private final ProgressDialog dialog = new ProgressDialog(RememberMe.this);
protected void onPreExecute()
{
this.dialog.setMessage("Listen werden geladen...");
this.dialog.show();
}
#Override
protected Void doInBackground(Void... arg0)
{
try
{
switch(startSynchronize())
{
case 0:
publishProgress(0);
return null;
case 1:
publishProgress(1);
return null;
case 2:
publishProgress(2);
return null;
}
}
catch (IOException e)
{
e.printStackTrace();
}
synchronize();
return null;
}
protected void onProgressUpdate(Integer... type)
{
int typeCase = type[0];
switch(typeCase)
{
case 0:
showDialog(DIALOG_INTERNET_ACCESS);
break;
case 1:
showDialog(DIALOG_CREATE_ACCOUNT);
break;
case 2:
showDialog(DIALOG_ACCOUNTS);
break;
}
}
protected void onPostExecute(final Void unused)
{
if (this.dialog.isShowing())
{
this.dialog.dismiss();
}
}
}
And here my startSynchronize() and synchronize() methods:
private int startSynchronize() throws IOException
{
googleAccountManager = new GoogleAccountManager(RememberMe.this);
Account[] accounts = googleAccountManager.getAccounts();
if(checkAccess.internetAccess() == false)
{
return 0;
}
if(accounts.length == 0)
{
return 1;
}
else
{
if(accounts.length == 1)
{
account = accounts[0];
}
else
{
return 2;
}
}
return -1;
}
private void synchronize()
{
myPrefs = this.getSharedPreferences("myPrefs", MODE_PRIVATE);
String oldToken = myPrefs.getString(MY_TOKEN, "");
if(oldToken.length() > 0)
{
// invalidate old token to be able to receive a new one
googleAccountManager.invalidateAuthToken(oldToken);
}
googleAccountManager.manager.getAuthToken(account, AUTH_TOKEN_TYPE, true, new AccountManagerCallback<Bundle>()
{
public void run(AccountManagerFuture<Bundle> future)
{
try
{
token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
prefsEditor.putString(MY_TOKEN, token);
prefsEditor.commit();
useTasksAPI(token);
}
catch (OperationCanceledException e)
{
//...
}
catch (Exception e)
{
//...
}
}
}, null);
}
In the Optionsmenu i start it like this
new SynchronizeGoogle().execute();
Thanks everybody for your help
If I do not misunderstand your question, you're wrong with getResult() method usage.
When getResult() called by anywhere in your code, AsyncTask does not wait until finish. So you need to do your process in onPostExecute method.
I recommend you this question&answer. I hope, it's gonna help you.