Обновление панели уведомлений из AsynTask приводит к сбою панели уведомлений

Я загружаю видеофайл с помощью асинхронной задачи. Чтобы отслеживать прогресс, у меня есть уведомление в строке состояния. Уведомление работает и обновляется правильно, но вызывает серьезные проблемы с производительностью, вплоть до сбоя строки состояния и необходимости перезагрузки телефона. Мой код выглядит следующим образом:

    private class UploadMedia extends AsyncTask<Void, Integer, String> {

    private int NOTIFICATION_ID = 1;
    private CharSequence _contentTitle;
    private final NotificationManager _notificationManager = (NotificationManager) getActivity()
            .getApplicationContext()
            .getSystemService(
                    getActivity().getApplicationContext().NOTIFICATION_SERVICE);
    Notification _notification;
    PendingIntent _pendingIntent;

    private long totalSize;
    private int _progress = 0;
    private InputStreamBody isb;
    private File uploadFile;

    protected void onPreExecute() {

        Intent intent = new Intent();
        _pendingIntent = PendingIntent.getActivity(getActivity(), 0,
                intent, 0);

        _contentTitle = "Uploader " + mediaTitle + " til Skoletube";
        CharSequence contentText = _progress + "% complete";

        _notification = new Notification(R.drawable.icon, _contentTitle,
                System.currentTimeMillis());
        _notification.flags = _notification.flags
                | Notification.FLAG_ONGOING_EVENT;
        _notification.contentIntent = _pendingIntent;
        _notification.setLatestEventInfo(getActivity(), _contentTitle,
                contentText, _pendingIntent);

        _notificationManager.notify(NOTIFICATION_ID, _notification);

        Toast.makeText(getActivity(), "Starter upload", Toast.LENGTH_SHORT)
                .show();

        try {
            uploadFile = new File(_mediaFile.getPath());

            // FileInputStream is = new FileInputStream(uploadFile);
            //
            // ByteArrayOutputStream bos = new ByteArrayOutputStream();
            // byte[] b = new byte[1024];
            // int bytesRead;
            // while ((bytesRead = is.read(b)) != -1) {
            // bos.write(b, 0, bytesRead);
            // }
            // byte[] data = bos.toByteArray();
            //
            // isb = new InputStreamBody(new ByteArrayInputStream(data),
            // uploadFile.getName());

        } catch (Exception ex) {
            Log.i(TAG,
                    "Pre execute - oh noes... D: "
                            + ex.getLocalizedMessage());
        }

    }

    @Override
    protected String doInBackground(Void... params) {
        String result = "";
        try {
            // Inititate connectionparts
            HttpClient client = new DefaultHttpClient();
            HttpPost postRequest = new HttpPost(
                    "http://www.skoletube.dk/beta/api_userupload.php");

            CustomMultipartEntity multipartE = new CustomMultipartEntity(
                    HttpMultipartMode.BROWSER_COMPATIBLE,
                    new ProgressListener() {

                        @Override
                        public void transferred(long num) {
                            publishProgress((int) ((num / (float) totalSize) * 100));

                        }
                    });

            // Add the post elements
            String timestamp = String
                    .valueOf(System.currentTimeMillis() / 1000);
            String mode = "xml";
            String hashSum = Utils.md5(ActiveUser.getPartner() + timestamp
                    + ActiveUser.getInstance().getToken()
                    + ActiveUser.getInstance().getSecret()
                    + ActiveUser.getInstance().getUserID()
                    + spnChannel.getSelectedItem().toString()
                    + mediaDescribtion + "KEYWORDLOL"
                    + spnPublic.getSelectedItem().toString() + mediaTitle
                    + ActiveUser.getSharedkey());

            multipartE.addPart("uid", new StringBody(ActiveUser
                    .getInstance().getUserID()));
            multipartE.addPart("token", new StringBody(ActiveUser
                    .getInstance().getToken()));
            multipartE.addPart("token_secret", new StringBody(ActiveUser
                    .getInstance().getSecret()));
            multipartE.addPart("partner",
                    new StringBody(ActiveUser.getPartner()));
            multipartE.addPart("timestamp",
                    new StringBody(timestamp.toString()));
            multipartE.addPart("key", new StringBody(hashSum));
            multipartE.addPart("video_title", new StringBody(mediaTitle));
            multipartE.addPart("video_desc", new StringBody(
                    mediaDescribtion));
            multipartE.addPart("video_keyword",
                    new StringBody("KEYWORDLOL"));
            multipartE.addPart("video_privacy", new StringBody(spnPublic
                    .getSelectedItem().toString()));
            multipartE.addPart("video_channel", new StringBody(spnChannel
                    .getSelectedItem().toString()));
            multipartE.addPart("videoupload", new FileBody(uploadFile));

            postRequest.setEntity(multipartE);

            totalSize = multipartE.getContentLength();


            HttpResponse loginResponse = client.execute(postRequest);
            HttpEntity theEnt = loginResponse.getEntity();
            result = EntityUtils.toString(theEnt);

            Log.i(TAG, "Result: " + result);

        } catch (Exception ex) {
            Log.i(TAG,
                    "Do in background - oh noes... D: "
                            + ex.getLocalizedMessage());

        }
        return result;
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        if (_notification == null)
            return;
        _progress = progress[0];
        _contentTitle = "Uploader " + mediaTitle + " til Skoletube";
        CharSequence contentText = _progress + "% complete";
        _notification.setLatestEventInfo(getActivity(), _contentTitle,
                contentText, _pendingIntent);
        _notificationManager.notify(NOTIFICATION_ID, _notification);
    }

    @Override
    protected void onPostExecute(String result) {
        _notificationManager.cancel(NOTIFICATION_ID);
    }

}

Я тестирую это на HTC Sensation. Проблемы возникают в тот момент, когда я нажимаю на панель уведомлений, в результате чего она расширяется. Телефон зависает, и его касание происходит независимо от того, действительно ли я доберусь до панели уведомлений или панель уведомлений рухнет. Если я доберусь до панели уведомлений, проблемы с производительностью сохраняются, и снова закрыть панель уведомлений так же сложно, как и открыть ее. Я думаю, что, возможно, причиной проблемы может быть огромное количество отправленных обновлений уведомлений, но я не уверен.

Ценю любые идеи и предложения.


person Line    schedule 22.02.2012    source источник


Ответы (2)


Ваши подозрения верны. Следующая инструкция

publishProgress((int) ((num / (float) totalSize) * 100));

будет вызываться очень часто, с короткими интервалами.

Что бы я сделал в такой ситуации, так это сохранил бы поток, который я хочу отобразить, и отправил бы его, только если он изменился с момента последнего звонка.

В методе doInBackground вы можете объявить переменную, например:

int lastPourcent = 0;

Затем в методе transferred:

int currentPoucent = (int) ((num / (float) totalSize) * 100);
if (currentPourcent > lastPourcent) {
    publishProgress(currentPourcent);
    lastPourcent = currentPourcent;
}

Это значительно уменьшит количество вызовов метода обновления уведомления.

person Romain R.    schedule 22.02.2012

Проблема в том, что ваш код переполняет службу Notification обновлениями каждый раз, когда вы выполняете publishProgress(). Что я сделал, и что вы должны сделать, так это реализовать решение, которое не переполняет сервис, а вместо этого заставляет ваш код обновлять Notification примерно каждые пять или десять процентов.

person Wroclai    schedule 22.02.2012