Question

I am attempting to use an Intent Service to run in the background to send email with fairly large (1-2mb) image attachments. I am a beginner, and have learned everything so far by researching on the web (so you may see some similar code).

What happens is that when I send the first email, everything works fine. However when I attempt to send another while the first is still processing, the first is dropped and the second goes through fine. It will always send the most recent of the queued intents and skip the ones before it.

From the research I have done, IntentService is supposed to queue the intents passed to it, and execute them sequentially in order. This question: IntentService : How to enqueue correctly? is similar, but I don't think it applies to my situation exactly.

I am sure I am missing something dumb =(

This is the onActivityResult where I start the service:

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.i(TAG, "Entered onActivityResult");
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_CANCELED) {
        Log.i(TAG, "onActivityResult Canceled");
        Toast toast = Toast.makeText(this,"Camera Canceled", 10000);
        toast.show();
        return;
    }
    if ((requestCode == CAMERA_PIC_REQUEST) && (resultCode == Activity.RESULT_OK)) {
        Log.i(TAG, "onActivityResult Result OK");
        String filePath = getOutputPath();
        String order = getOrder();
        Log.i(TAG, "Sending From: " + filePath);
        Intent sendIntent = new Intent(this, MailIntentService.class);
        sendIntent.putExtra(MailIntentService.IN_SUBJECT, order);
        sendIntent.putExtra(MailIntentService.IN_PATH, filePath);
        startService(sendIntent);
        Toast.makeText(this, "Image Upload Started.  Check Notification Bar for Status.", Toast.LENGTH_LONG).show();
    }
}

This is the entire IntentService:

public class MailIntentService extends IntentService {
//These set the parameters for the Email
public static final String destEmail = "hidden";
public static final String sendEmail = "hidden";
public static final String sendPass = "hidden";
public static final String body = "GrowerLive image upload request.";
public static final String IN_SUBJECT = "insub";
public static final String IN_PATH = "inpath";

//This is the standard tag for class name
private static final String TAG = MailIntentService.class.getSimpleName();

//These set up the parameters for notifications
private NotificationManager mNotificationManager;
private Notification notifyDetails;
private int NOTIFICATION_ID;
private CharSequence contentTitle = "Bethel Upload";
private CharSequence contentText = "Image Uploading...";
private String contentTicker = "Upload Started...";

public void onCreate() {
    super.onCreate();
    Log.i(TAG, "MailIntentService Created");
    mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
    notifyDetails = new Notification(R.drawable.ic_launcher, contentTicker, System.currentTimeMillis());
}

public void onDestroy() {
    super.onDestroy();
    File dir = new File(Environment.getExternalStorageDirectory() + "/BethelUpload");
    if (dir.isDirectory()) { 
        String[] children = dir.list(); 
        for (int i = 0; i < children.length; i++) { 
            new File(dir, children[i]).delete(); 
        } 
    }
    Log.i(TAG, "MailIntentService Destroyed");
}

public MailIntentService() {
    super(TAG);
}

@Override
protected void onHandleIntent(Intent intent) {

    Context context = getApplicationContext();
    Intent notifyIntent = new Intent(BethelUploadActivity.class.getSimpleName());
    PendingIntent intentP = PendingIntent.getActivity(MailIntentService.this, 0, notifyIntent, android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
    notifyDetails.setLatestEventInfo(context, contentTitle, contentText, intentP);

    try {
        String subject = intent.getStringExtra(IN_SUBJECT);
        String path = intent.getStringExtra(IN_PATH);

        Log.i(TAG, "Sending Mail...");
        Log.i(TAG, "Subject: " + subject);
        Log.i(TAG, "Attachment Path: " + path);
        mNotificationManager.notify(NOTIFICATION_ID, notifyDetails);

        GMailSender sender = new GMailSender(sendEmail, sendPass); 
        sender.sendMail(subject, body, sendEmail, destEmail, path);

        Log.i(TAG, "Mail Sent!");
        contentText = "Image Uploaded Successfully";
        contentTicker = "Upload Successful";
        notifyDetails.setLatestEventInfo(context, contentTitle, contentText, intentP);
        mNotificationManager.notify(NOTIFICATION_ID, notifyDetails);
    } 
    catch (Exception e) {    
        Log.e(TAG, e.getMessage(), e);    
    }       
}
}

This is the GMailSender I use from another example here: Sending Email in Android using JavaMail API without using the default/built-in app

public class GMailSender extends javax.mail.Authenticator {    
    private String mailhost = "smtp.gmail.com";    
    private String user;    
    private String password;    
    private Session session;

static {    
    Security.addProvider(new com.provider.JSSEProvider());    
}   

public GMailSender(String user, String password) { 

    this.user = user;    
    this.password = password;    

    Properties props = new Properties();    
    props.setProperty("mail.transport.protocol", "smtp");    
    props.setProperty("mail.host", mailhost);    
    props.put("mail.smtp.auth", "true");    
    props.put("mail.smtp.port", "465");    
    props.put("mail.smtp.socketFactory.port", "465");    
    props.put("mail.smtp.socketFactory.class",    
            "javax.net.ssl.SSLSocketFactory");    
    props.put("mail.smtp.socketFactory.fallback", "false");    
    props.setProperty("mail.smtp.quitwait", "false");    

    session = Session.getDefaultInstance(props, this);    
}    

protected PasswordAuthentication getPasswordAuthentication() {    
    return new PasswordAuthentication(user, password);    
}    

public synchronized void sendMail(String subject, String body, String sender, String recipients, String fileAttachment) throws Exception {

    try{ 
    MimeMessage message = new MimeMessage(session);    
    message.setSender(new InternetAddress(sender));    
    message.setSubject(subject);

    MimeBodyPart messageBodyPart = new MimeBodyPart();
    messageBodyPart.setText(body);

    Multipart multipart = new MimeMultipart();
    multipart.addBodyPart(messageBodyPart);

    messageBodyPart = new MimeBodyPart();
    DataSource source = new FileDataSource(fileAttachment);
    messageBodyPart.setDataHandler(new DataHandler(source));
    messageBodyPart.setFileName("SodPhoto.jpg");
    multipart.addBodyPart(messageBodyPart);

    message.setContent(multipart);

    if (recipients.indexOf(',') > 0)
        message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients));
    else
        message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipients));
    Transport.send(message);
    }catch(Exception e){

    }
}

public class ByteArrayDataSource implements DataSource {
    private byte[] data;
    private String type;

    public ByteArrayDataSource(byte[] data, String type) {
        super();
        this.data = data;
        this.type = type;
    }

    public ByteArrayDataSource(byte[] data) {
        super();
        this.data = data;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getContentType() {
        if (type == null)
            return "application/octet-stream";
        else
            return type;
    }

    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(data);
    }

    public String getName() {
        return "ByteArrayDataSource";
    }

    public OutputStream getOutputStream() throws IOException {
        throw new IOException("Not Supported");
    }
}
}

I know this is a huge amount of code / wall of text, but I figured I would rather give you too much information than too little. I really appreciate your time!

Was it helpful?

Solution 2

After figuring out that using SystemClock.sleep(30000) (thanks to DineshKumar below) will fix my problem, I did some research and found that network calls do not always block an IntentService. SystemClock.sleep(30000) does block the IntentService, but it makes it wait 30 seconds even if it doesn't need to (not optimal).

I then figured out a way to check to see if my GMailSender class was processing:

private boolean isSending() {
        ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        List<RunningAppProcessInfo> runningProcInfo = manager.getRunningAppProcesses();
        for(int i = 0; i < runningProcInfo.size(); i++) {
        if(runningProcInfo.get(i).processName.equals("com.bethelfarms.bethelupload.GMailSender")) {
            Log.i(TAG, "isSending is true");
            return true;
        }
    }
    Log.i(TAG,"isSending is false");
    return false;
}

And then I placed a while loop in my IntentService that blocks the code until it sees that GMailSender is finished processing:

        GMailSender sender = new GMailSender(sendEmail, sendPass);  
        //Blocking action to wait for previous message to send
        sent = isSending();
        while(sent==true) {
            SystemClock.sleep(1000);
            sent = isSending();
        }
        sender.sendMail(subject, body, sendEmail, destEmail, path); 

OTHER TIPS

I think this will be solution...

     GMailSender sender = new GMailSender(sendEmail, sendPass); 
         SystemClock.sleep(30000);
    sender.sendMail(subject, body, sendEmail, destEmail, path);

This makes your first mail sends at 30seconds delayed from current System time and second one also sends like this manner...

use the requestcode in pendingIntent..it's your code

   PendingIntent intentP = PendingIntent.getActivity(MailIntentService.this, 0,     notifyIntent, android.content.Intent.FLAG_ACTIVITY_NEW_TASK);

see why your first mail is not sended but the last one sends the problem is use request code in pending intent i.e to create a separate a id for each pending intent..i will show aome simple example..

    int COUNT=Integer.parseInt(some_txt.getText().toString());

    if(COUNT==1)  
     { 
        PendingIntent intentP = PendingIntent.getService(MailIntentService.this, COUNT,     notifyIntent, android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
     }
   else if(COUNT==2)
   {
       PendingIntent intentP = PendingIntent.getActivity(MailIntentService.this, COUNT,     notifyIntent, android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
    }
  else if(COUNT==3)
  {
     PendingIntent intentP = PendingIntent.getActivity(MailIntentService.this, COUNT,     notifyIntent, android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
   }

see instead of using startService() directly try pendingIntent with AlarmManager so you send mail at specified time i hope this will helps you..

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top