Android的服务启动 [英] Android Service start

查看:117
本文介绍了Android的服务启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建服务来下载电影和notificate进步,我发现了一个问题,当我开始下载,然后从应用程序退出我的服务创造新的不破坏previous之一。

i created Service to download movies and notificate progress, and i found a problem when i start downloading and then exit from app my Service create new without destroying the previous one.

日志:

 CREATE  // I press Download button Service Created
 START  
 RUN
 CREATE  // I exit from app and it creates new, without DESTROY
 START
 RUN    
 START   // I press to stop downloading
 DESTROY

DownloadManager.java

public class DownloadManager extends Service{



private ExecutorService exec;

private int mb = 1024*1024;
private int Notifid;
private int progressPercent;

private String title;
private String url;

private boolean serviceWork = true;

private NotificationManager manager;
private NotificationCompat.Builder builder;

@Override
public void onCreate() {
    super.onCreate();   
    exec = Executors.newFixedThreadPool(1);
    builder = new NotificationCompat.Builder(getApplicationContext());
    manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    url = intent.getStringExtra(C.SERVICE_URL);
    title = intent.getStringExtra(C.SERVICE_TITLE);

    if(url.equals("cancel")){
     stopSelf();
    }       
    else {          
        Run run = new Run(url, title);
        serviceWork = true;
        exec.execute(run);
    }

    Notifid = 0x45;

    return START_REDELIVER_INTENT;
}

@Override
public void onDestroy() {
    if(url.equals("cancel")){
        cancel();
    }           
    serviceWork = false;
    super.onDestroy();
}


void generateNotify(String msg1, String msg2){              
    builder.setAutoCancel(false);
    builder.setOngoing(true);
    builder.setContentTitle(msg1);
    builder.setContentText(msg2);
    builder.setSmallIcon(R.drawable.ic_launcher, 0);
    builder.setTicker(msg1);
    builder.setProgress(0, 0, true);

    Intent intent = new Intent(this, DownloadManager.class);
    intent.putExtra(C.SERVICE_URL, "cancel");
    PendingIntent pending = PendingIntent.getService(this, 0, intent, 0);
    builder.setContentIntent(pending);
    manager.notify(Notifid, builder.build());   

}

void progress(final int progress, final String msg){
    new Thread(
            new Runnable() {
                @Override
                public void run() {
                    builder.setProgress(100, progress, false);
                    builder.setContentText(msg);
                    manager.notify(Notifid, builder.build());   
                }
         }
    ).start();
}

void ticker(String msg1){
    builder.setTicker(msg1);
    builder.setContentText(msg1);
    manager.notify(Notifid, builder.build());   
}

void cancel(){
    manager.cancel(Notifid);
}

void cancable(){
    builder.setOngoing(false);

    Intent intent  = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.parse("sdcard/Mover/"+title+".mp4"), "video/*");

    PendingIntent pending = PendingIntent.getActivity(this, 0, intent, 0);
    builder.setContentIntent(pending);
    builder.setAutoCancel(true);

    manager.notify(Notifid, builder.build());
}

class Run implements Runnable{

    private String url;
    private String title;

    private int count;
    private int fileLength;

    public Run(String url, String title) {
        this.url = url;
        this.title = title;
    }

    @Override
    public void run() {

        try{

            // Создаем подключение к ссылке.

            URL openUrl = new URL(url);
            URLConnection connection = openUrl.openConnection();
            connection.connect();

            // Проверяем наличие папки если отсуствует создаем.

            File file = new File("sdcard/Mover/");
            file.mkdirs();

            // Размер файла

            fileLength = connection.getContentLength();

            // Загружаем конетнт

            InputStream ips = new BufferedInputStream(openUrl.openStream());
            OutputStream ops = new FileOutputStream("sdcard/Mover/"+title+".mp4");

            // Показываем уведомление
            DownloadManager.this.generateNotify(title, "Всего: " +format(fileLength));

            byte[] data = new byte[1024];
            int total = 0;
            int last = 0;
            int progress = 1;
            int lasttotal = 0;

            int speed = 0;

            long current = System.currentTimeMillis();
            // Читаем
            while ((count = ips.read(data)) != -1) {
                if(serviceWork){
                    ops.write(data, 0, count);                  
                    total += count;    

                    long now = System.currentTimeMillis();

                    // Определяем скорость загрзки. 
                    // Для этого делаем  проверку на каждую секунду
                    if(now > current + 1000){
                        current = now;

                        speed = (total - lasttotal)/1024;                       
                        lasttotal = total;
                    }


                    progressPercent = (total*100)/fileLength;
                    if(last != progressPercent){
                        last = progressPercent;
                        progress++;
                        DownloadManager.this.progress(progress, "Всего: " +format(fileLength) + " / " + format(total) + " / " + speed + "KB/s");                            
                    }
                }
            }

            ops.flush();
            // Закрываем 

            ops.close();
            ips.close();

        }
        catch(Exception e){
            e.printStackTrace();
        }

        finish();           
    }

    void finish(){
        DownloadManager.this.ticker("Загрузка успешно завершена.");
        DownloadManager.this.stopSelf();
        DownloadManager.this.cancable();
    }

    void stop(){
        DownloadManager.this.stopSelf();
        DownloadManager.this.cancel();
    }

}


public String format(int m){

    String size = m%mb+"";
    size = size.substring(0, Math.min(size.length(), 2));

    return m/mb + "." + size + "мб";
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

}

推荐答案

从检查你的 onStartCommand 我可以看到你指定的 START_REDELIVER_INTENT 。的Javadoc这种类型的返回标志状态;

From inspecting the return flag specified in your onStartCommand I can see you have specified START_REDELIVER_INTENT. The Javadoc for this type of return flag states;

如果同时启动这个服务的过程中被杀死(后
  从onStartCommand(意向,INT,INT))返回,那么这将是
  定于重新启动和最后交付意向重新交付给
  再次通过onStartCommand(意向,INT,INT)

if this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), then it will be scheduled for a restart and the last delivered Intent re-delivered to it again via onStartCommand(Intent, int, int)

从这个解释很明显,你的服务被杀害。这样做的原因还不清楚,但要确保服务(和他们的子线程)仍然活着是我曾与前搏斗。在我们的应用中,我们发现,手机里睡觉是特别破坏性的。我们通过给该服务的唤醒锁和WiFi锁,以确保(一)服务没有封存睡眠及(b)系统保持一个WiFi锁定'黑客'(?)围绕这些细微之处(即没有挂断活动wifi连接),而我们有工作,我们的子线程来做。请看看你的服务的行为睡眠环境下之后,我们为您答疑解惑。
然而,这个标志似乎可以解释你的服务的表观重启和下载重新尝试。

From this explanation it is apparent that your service is being killed. The reason for this is unclear but ensuring Services (and their child threads) remain 'alive' is something I have grappled with before. In our application we found that phone sleeps were particularly destructive. We 'hacked' (?) around these nuances by giving the service a Wake-Lock and WiFi-Lock to ensure (a) the Service wasn't mothballed on sleep and (b) the system kept a wifi lock (i.e. didn't drop the active wifi connection) whilst we had work to do in our child threads. Please look into your Service's behaviour under a sleep environment after we get this sorted. Nonetheless, this flag seems to explain the apparent restarting of your service and the download re-attempt.

从简单地回顾一下你的code我看到你从你的线程您的服务进行通信。一个 IntentService 也许适用于这种情况下作为Ranjith指出。然而,子线程无法与剥离工作线程的服务进行通信。这样做的原因是,托管服务,因为该服务的工作是与所有剩下的工作被异步完成完成分拆工作线程后立即死亡。这可以解释为什么这并不为你工作。

From briefly reviewing your code I see that you are communicating with your service from your thread. An IntentService maybe applicable in this scenario as Ranjith points out. However, the child thread cannot communicate with the Service which spun off the worker thread. The reason for this is that the hosting service is almost immediately killed after spinning off the worker thread since the service's job is done with all remaining work being completed asynchronously. This could explain why this didn't work for you.

要与此前进我会尝试以下步骤之一;

To move forward with this I would attempt one of the following;


  1. 使用的 IntentService 上下移动所有通知code到线程,并断绝一切的AsyncTask-服务的通信。请注意我关于WakeLocks和WiFiLocks网络通讯科提出的意见。如果不小心。使用这些工具出现电池相当危险

  2. 如果你想,只要​​你的子线程,那么我建议从服务返回 START_STICKY 标记,并允许您的应用程序绑定到它的服务存在(REF :绑定服务来看看它是如何获得的

  1. Use an IntentService and move all notification code down into the thread and sever all AsyncTask-Service communications. Please also note the comments I made regarding WakeLocks and WiFiLocks for network comms. These tools appear quite dangerous for the Battery if used without care.
  2. If you want your service to exist as long as your child thread then I would suggest returning the START_STICKY flag from your service and allowing your app to bind to it (ref: Bound Service to see how it's getting on.

这篇关于Android的服务启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆