繁体   English   中英

当用户从最近的应用程序中关闭应用程序时,Sticky Service被杀死

[英]Sticky Service is getting killed when user closes app from recent apps

我有启动和使用基本服务的良好概念。 我的意思是不复杂。 在“我的应用程序”中,我想要一种在任何情况下都不应被杀死的服务,并且应该从服务器下载一些文件,然后应调用stopSelf。 我已经通过以下方式提供服务。 但是在分享全部代码之前,我先告诉你我在做什么

  1. 在Service中,我传递了一系列的url(字符串数组),它必须从服务器下载所有文件。
  2. 我正在使用异步任务从服务器下载。
  3. 在整个过程中,我得到了xml中的第一个响应,然后对其进行了解析,并获取了JSON字符串(对不起,我的Web服务设计者像我一样麻木)。 因此,在这两次转换之后,我将数据存储在数据库中,然后开始下载文件并将其保存到设备,并将其路径存储在数据库中。 (一切正常)
  4. 我正在计算和更新通知栏中的进度。 (向用户显示已下载了多少文件)

我真正想要的

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

到底发生了什么

当我从最近的应用程序托盘中关闭我的应用程序时,我认为我的服务被终止并且下载过程停止,并且它也停止更新通知栏中通知的进度,而我希望它继续运行直到下载过程完成。

这是我的代码,因为有些方法确实不值得在这里讨论,所以它被简化了,例如解析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. 如果您想做网络工作,为什么不使用IntentService
  2. 您应该考虑添加setIntentRedelivery(true); 在您的构造函数中

文档中

设置意图重新交付首选项。 通常使用您首选的语义从构造函数中调用。

如果启用为true,则onStartCommand(Intent,int,int)将返回START_REDELIVER_INTENT,因此,如果此过程在onHandleIntent(Intent)返回之前终止,则该过程将重新启动并重新发送该intent。 如果发送了多个Intent,则只能保证最新的Intent被重新发送。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM