Работая с обработчиками и потоками в сервисе, Thread.sleep заставляет программу зависать?

#android

#Android

Вопрос:

я работаю над приложениями для планировщика задач в качестве моего проекта в колледже, у меня есть сервис, который проверяет время истечения задачи. я внедрил обработчики для проверки времени истечения срока действия. Когда время истечения срока действия приложения совпадает с текущим временем, оно отправляет уведомление в строке состояния. На данный момент я приостанавливаю поток, используя метод Thread.sleep, на минуту, что приводит к зависанию моего приложения. В logcat это показывает интенсивное использование процессора приложениями.

я извлекаю данные из базы данных, но это работает нормально, когда Thread.sleep не вызывается. Пожалуйста, помогите.

Вот код:

 package com.apps.niit.taskm;
import java.util.ArrayList;
import java.util.Calendar;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;


public class ExpireTimeService extends Service {

    DataHelper dh;
    ArrayList<String> tData=new ArrayList<String>();
    String date;
    Calendar c;
    String str;
    String str1;
    String str2;
    String str3;
    String str4;
    String str5;
    int notificationID=1;
    String [][] data;
    NotificationManager notificationManager;
    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public void onCreate(){
        super.onCreate();
        dh = new DataHelper(this);
        fetchData();
        handler.removeCallbacks(updateTimeTask);
        handler.postDelayed(updateTimeTask, 1000);  
    }
    public void fetchData(){
        String eDate = android.text.format.DateFormat.format("d/M/yyyy", new java.util.Date()).toString();
        tData.addAll(this.dh.selectDate(eDate));
        data =new String[tData.size()][4];
        if(!tData.isEmpty()){
            for(int i=0; i<tData.size();i  ){
                breakString(tData.get(i));
                data[i][0]=str1;
                data[i][1]=str2;
                data[i][2]=str3;
                data[i][3]=str4;
            }
        }
    }

    public void stopService(){
        stopSelf();
    }
    private Runnable updateTimeTask = new Runnable() {
        public void run(){
            try {
                String time = android.text.format.DateFormat.format("k:m", new java.util.Date()).toString();

                for(int i=0; i<tData.size();i  ){
                    if(data[i][3].equals(time)){
                    //send notification code goes here
                        String serName = Context.NOTIFICATION_SERVICE;
                        notificationManager = (NotificationManager)getSystemService(serName);               
                        String ticker= data[i][0] " " data[i][1] " " data[i][2] " " data[i][3];
                        long when= System.currentTimeMillis();
                        int icon = R.drawable.icon;
                        Notification notification = new Notification(icon, ticker,when);
                        Intent intent = new Intent (getApplicationContext(), DisplayTask.class);
                        Bundle myBundle = new Bundle();     
                        myBundle.putString("str1", data[i][0]);
                        myBundle.putString("str2", data[i][1]);Log.i("data1",data[i][1]);
                        myBundle.putString("str3", data[i][2]);Log.i("data1",data[i][2]);
                        myBundle.putString("str4", data[i][3]);Log.i("data1",data[i][3]);
                        intent.putExtras(myBundle);
                        PendingIntent launchIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
                        notification.setLatestEventInfo(getApplicationContext(), "", "", launchIntent);
                        notificationID=1;
                        notificationManager.notify(notificationID, notification);
                        Thread.sleep(10000);                    
                    }
                }
                handler.postDelayed(this, 1000);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                Log.e("Error from service", e.toString());
            }
        }       
    };

    private void breakString(String str) {
        // TODO Auto-generated method stub
        str1 = str.substring(0, str.indexOf(";"));
        str = str.substring(str1.length() 1, str.length());
        str2 = str.substring(0, str.indexOf(";"));
        str = str.substring(str2.length() 1, str.length());
        str3 = str.substring(0, str.indexOf(";"));
        str4 = str.substring(str3.length() 1, str.length());
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (handler != null)
            handler.removeCallbacks(updateTimeTask);
        handler = null;
    }
    private Handler handler = new Handler();
}
  

Ответ №1:

Когда вы используете Handler postDelayed функцию, вот что происходит:

  1. Обработчик помещает ваш Runnable в очередь циклирования текущего потока.
  2. Когда придет время, ваш код Runnable будет запущен в потоке пользовательского интерфейса.

Обратите внимание, что это не то, что Handler всегда помещает Runnable в очередь потоков пользовательского интерфейса. Это помещает Runnable в очередь текущего потока, а вашим текущим потоком был поток пользовательского интерфейса.

Итак, если вы добавите Thread.sleep или что-нибудь еще, требующее много времени (например, сетевое взаимодействие), updateTimeTask это приведет к зависанию всего потока пользовательского интерфейса.

В вашем случае вам следует использовать ScheduledExecutorService , см. scheduleWithFixedDelay функцию. Или, в качестве альтернативы, вы можете начать AsyncTask со своей updateTimeTask функции и выполнять всю тяжелую работу Thread.sleep в doInBackgrund функции.

Комментарии:

1. проблема решена с помощью другой альтернативы, использующей handler.postDelayed(<time>); notifyAll(); но возникла другая проблема — он будет отправлять только одно уведомление в минуту. например, в моем коде есть две задачи с одинаковым временем, тогда он будет показывать уведомление только за это время.

2. другим решением этой проблемы является время сопоставления в формате hh: mm: ss