当用户从最近的应用程序关闭应用程序时,粘性服务就会被杀死

时间:2015-11-12 06:55:39

标签: android android-service

我有很好的启动和使用基本服务的概念。我的意思是不要复杂。在我的应用程序中,我想要一个不应该在任何情况下被杀死的服务,并且应该从服务器下载一些文件,然后它应该调用stopSelf。我以下列方式提供服务。但在分享整个代码之前,让我告诉你我在做什么

  1. 在服务中我传递了一系列url(字符串数组),它必须从服务器下载所有文件。
  2. 我正在使用异步任务从服务器下载。
  3. 在整个过程中,我得到第一个响应,在xml中,然后我解析它,并获取JSON字符串(抱歉我的Web服务设计师像我一样麻木)。所以在这两次转换之后,我将数据存储在数据库中,然后开始下载文件并将它们保存到设备并将其路径存储在数据库中。 (这一切都很好)
  4. 我正在计算和更新通知栏中的进度。 (向用户显示已下载文件的数量)
  5. 我真正想要的是什么

    我希望当用户将其从最近的应用列表中删除时,我的服务不会被杀死,因此它应该继续下载并继续更新通知栏中的状态。我正在使用通知管理器来更新进度。

    真实情况

    当我从最近的应用程序托盘关闭我的应用程序时,我认为我的服务被杀死并且下载过程停止,并且它还停止更新通知栏中的通知进度,其中我希望它继续运行直到下载过程结束了。

      

    这是我的代码,它被简化,因为有些方法真的不值得   这里讨论如解析xml或JSON

    以下是代码

    public class MyDemoService extends Service {
    private static final String TAG = "MyDemoService";
    private static final int NOTIFICATION_ID = 1;
    private LocalBinder m_binder = new LocalBinder();
    private NotificationManager mNotifyManager;
    private NotificationCompat.Builder mBuilder;
    myAsyncTask myWebFetch;
    // Timer to update the ongoing notification
    private final long mFrequency = 100;    // milliseconds
    private final int TICK_WHAT = 2;
    
    public class LocalBinder extends Binder {
        MyDemoService getService() {
            return MyDemoService.this;
        }
    }
    
    private Handler mHandler = new Handler() {
        public void handleMessage(Message m) {
            updateNotification();
            sendMessageDelayed(Message.obtain(this, TICK_WHAT), mFrequency);
        }
    };
    
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "bound");
    
        return m_binder;
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "created");
        mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return Service.START_STICKY;
    }
    
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.d(TAG, "Removed");
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "Destroyed");
    }
    
    
    public void updateNotification() {
        // Log.d(TAG, "updating notification");
    
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    
    }
    
    
    public void hideNotification() {
        Log.d(TAG, "removing notification");
        mNotifyManager.cancel(NOTIFICATION_ID);
        mHandler.removeMessages(TICK_WHAT);
    }
    
    public void start() {
        Log.d(TAG, "start");
        mBuilder =
                new NotificationCompat.Builder(MyDemoService.this)
                        .setSmallIcon(R.drawable.download)
                        .setContentTitle("SMU")
                        .setContentText("Downloading Images");
        Intent targetIntent = new Intent(MyDemoService.this, MainActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(MyDemoService.this, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        mBuilder.setContentIntent(contentIntent);
        mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
        myWebFetch = new myAsyncTask();
        myWebFetch.execute();
    }
    
    class myAsyncTask extends AsyncTask<String, Integer, Void> {
        MyDB myDB;
    
    
        myAsyncTask() {
            myDB = new MyDB(MyDemoService.this);
        }
    
        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            mBuilder.setContentText("Download complete");
            // Removes the progress bar
            mBuilder.setProgress(0, 0, false);
            mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
        }
    
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            mBuilder.setProgress(100, values[0], false);
            mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
        }
    
        @Override
        protected Void doInBackground(String... params) {
            //set the download URL, a url that points to a file on the internet
            getJSON("http://*****", 1000000);
            return null;
        }
    
    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mBuilder.setProgress(100, 0, false);
            mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
        }
    
        public void getJSON(String url, int timeout) {
            HttpURLConnection c = null;
            try {
                URL u = new URL(url);
                c = (HttpURLConnection) u.openConnection();
                c.setRequestMethod("GET");
                c.setUseCaches(false);
                c.setAllowUserInteraction(false);
                c.setConnectTimeout(timeout);
                c.setReadTimeout(timeout);
                c.setInstanceFollowRedirects(false);
                c.connect();
                int status = c.getResponseCode();
    
                if (status == 200) {
                    String readStream = readStream(c.getInputStream());
                    if (readStream != null) {
                        JsonParser mJsonParser = new JsonParser(MyDemoService.this);
                        mJsonParser.parseJaSon(readStream);
                        ArrayList<SuitDetails> mImageList = new ArrayList<>(myDB.GetAllData());
    
                        if (mImageList != null) {
                            //NOW HERE DOWNLOADING IMAGES FROM URL WE GOT SAVED IN DB AFTER PARSING
                            downloadImages(mImageList);
    
                        }
                    }
    
                }
    
            } catch (MalformedURLException ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
            } finally {
                if (c != null) {
                    try {
                        c.disconnect();
                    } catch (Exception ex) {
                        Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
    
        }
    
        @TargetApi(Build.VERSION_CODES.KITKAT)
        private String readStream(InputStream in) {
            //parsing my input stream and sending back string
            return jsonString.toString();
        }
    
        void downloadImages(ArrayList<SuitDetails> arrayList) {
    
            try {
    
                ArrayList<SuitDetails> imageUrl = arrayList;
                URL url;
                float progressImages = 0;
                HttpURLConnection urlConnection = null;
                for (int i = 0; i < imageUrl.size(); i++) {
                    progressImages += 100 / imageUrl.size();
                    publishProgress((int) progressImages);
                    url = new URL(imageUrl.get(i).getPath().toString());
                    //create the new connection
                    urlConnection = (HttpURLConnection) url.openConnection();
                    //set up some things on the connection
                    urlConnection.setRequestMethod("GET");
                    urlConnection.setDoOutput(false);
                    urlConnection.setUseCaches(false);
                    urlConnection.setAllowUserInteraction(false);
                    urlConnection.setConnectTimeout(60000);
                    urlConnection.setReadTimeout(60000);
                    urlConnection.setInstanceFollowRedirects(false);
                    //and connect!
                    urlConnection.connect();
                    File storagePath = new File(MyDemoService.this.getExternalFilesDir("TEST") + "/Mytest");
                    storagePath.mkdirs();
                    String finalName = imageUrl.get(i).getImageName();
                    File myImage = new File(storagePath, finalName + ".png");
                    FileOutputStream fileOutput = new FileOutputStream(myImage);
                    InputStream inputStream = urlConnection.getInputStream();
                    int totalSize = urlConnection.getContentLength();
                    int downloadedSize = 0;
                    byte[] buffer = new byte[1024];
                    int bufferLength = 0;
                    while ((bufferLength = inputStream.read(buffer)) > 0) {
                        //add the data in the buffer to the file in the file output stream (the file on the sd card
                        fileOutput.write(buffer, 0, bufferLength);
                        //add up the size so we know how much is downloaded
                        downloadedSize += bufferLength;
                        //this is where you would do something to report the prgress, like this maybe
                    }
                    //close the output stream when done
                    ContentValues contentValues = new ContentValues();
                    contentValues.put("Status", "1");
                    contentValues.put("Path", myImage.getPath().toString());
                    myDB.UpdateDownloadStatus(contentValues, imageUrl.get(i).getSImageID());
                    fileOutput.close();
                }
                myDB.closeDb();
                //catch some possible errors...
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }
    

    }

      

    我知道这是长度代码,但如果你想要深入分析它,请分享。

    如果您需要,我将提供我在MainActivity中使用和调用此服务的方式

1 个答案:

答案 0 :(得分:1)

  1. 如果你想做网络工作,你为什么不使用IntentService
  2. 您应该考虑在构造函数中添加setIntentRedelivery(true);
  3. 来自documentation

      

    设置意向转发首选项。通常叫做   具有您首选语义的构造函数。

         

    如果enabled为true,则返回onStartCommand(Intent,int,int)   START_REDELIVER_INTENT,所以如果此过程在此之前消失   onHandleIntent(Intent)返回,进程将重启并且   意图重新传递。如果已发送多个Intent,则仅发送最多   最近的一个保证被重新传递。

         

    如果enabled为false(默认值),onStartCommand(Intent,int,int)   将返回START_NOT_STICKY,如果进程终止,则Intent将死亡   随之而来。