Android: IntentService неправильно ставится в очередь
Я пытаюсь использовать Intent Service для запуска в фоновом режиме для отправки электронной почты с довольно большими (1-2 МБ) вложениями изображений. Я новичок, и до сих пор изучил все, исследуя в Интернете (так что вы можете увидеть некоторый похожий код).
Что происходит, когда я отправляю первое письмо, все работает нормально. Однако, когда я пытаюсь отправить другой, пока первый еще обрабатывает, первый сбрасывается, а второй проходит нормально. Он всегда будет отправлять самые последние из поставленных в очередь намерений и пропускать те, что были до него.
Из проведенного мною исследования IntentService должен ставить в очередь переданные ему намерения и последовательно выполнять их по порядку. Этот вопрос: IntentService: как правильно поставить в очередь? похоже, но я не думаю, что это относится именно к моей ситуации.
Я уверен, что я что-то упустил тупой =(
Это onActivityResult, где я запускаю службу:
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();
}
}
Это весь 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);
}
}
}
Это GMailSender, который я использую из другого примера: отправка электронной почты в Android с использованием API JavaMail без использования встроенного приложения по умолчанию
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");
}
}
}
Я знаю, что это огромный объем кода / стены текста, но я подумал, что лучше дать вам слишком много информации, чем слишком мало. Я очень ценю ваше время!
3 ответа
После выяснения, что с помощью SystemClock.sleep(30000)
(спасибо DineshKumar ниже) исправит мою проблему, я провел некоторое исследование и обнаружил, что сетевые вызовы не всегда блокируют IntentService
, SystemClock.sleep(30000)
блокирует IntentService
, но это заставляет его ждать 30 секунд, даже если это не нужно (не оптимально).
Затем я нашел способ проверить, обрабатывает ли мой класс GMailSender:
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;
}
И тогда я поместил while
петля в моем IntentService
который блокирует код, пока не увидит, что GMailSender завершил обработку:
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);
Я думаю, что это будет решением...
GMailSender sender = new GMailSender(sendEmail, sendPass);
SystemClock.sleep(30000);
sender.sendMail(subject, body, sendEmail, destEmail, path);
Это делает вашу первую почту отправленной с задержкой в 30 секунд от текущего системного времени, а вторая также отправляет таким образом...
Используйте код запроса в pendingIntent.. это ваш код
PendingIntent intentP = PendingIntent.getActivity(MailIntentService.this, 0, notifyIntent, android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
Вы поймете, почему ваше первое письмо не отправлено, но последнее отправляет проблему: используйте код запроса в ожидающем намерении, т. е. для создания отдельного идентификатора для каждого ожидающего намерения. Я покажу один простой пример.
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);
}
см. вместо того, чтобы использовать startService(), напрямую попробуйте pendingIntent с AlarmManager, чтобы вы отправляли почту в указанное время, надеюсь, это поможет вам..