如何解决android服务泄露错误

时间:2016-06-23 12:23:07

标签: java android android-studio memory-leaks android-service

我有一个在onCreate上调用服务的活动,但是当我尝试运行该项目时,我不断收到一条错误消息,说服务已经泄漏,并且对调用/注册它的活动有更长的限制。

“活动com.xera.deviceinsight.home.DataUsageActivity泄露了最初绑定在这里的ServiceConnection com.xera.deviceinsight.home.DataUsageActivity$3@42676a48”我假设这可能与活动的生命周期有关。我有下面的活动和服务

myActivity

 public class DataUsageActivity extends AppCompatActivity implements MonitorService.ServiceCallback
    {
     protected void onCreate(Bundle savedInstanceState)
       {
          super.onCreate(savedInstanceState);

          TinyDB settings = new TinyDB(this);
          if (settings.getBoolean(AppPreferences.HAS_LOGGED_IN))
          {


             this.bindService(
                     new Intent(this, MonitorService.class),
                     serviceConnection,
                     Context.BIND_AUTO_CREATE);
             return;
          }

          }


     public void sendResults(int resultCode, Bundle b)
       {
         // adapter.notifyDataSetChanged();
       }

         private ServiceConnection serviceConnection = new ServiceConnection()
       {
          @Override
          public void onServiceConnected(ComponentName className, IBinder service)
          {
             MonitorService.LocalBinder binder = (MonitorService.LocalBinder)service;
             backgroundService = binder.getService();
             backgroundService.setCallback(DataUsageActivity.this);
             backgroundService.start();
          }

          @Override
          public void onServiceDisconnected(ComponentName className)
          {
             backgroundService = null;
          }
       };


        @Override
       public void onResume()
       {
          super.onResume();
          if(backgroundService != null)
          {
             backgroundService.setCallback(this);
          }
       }


       @Override
       public void onPause()
       {
          super.onPause();
          if(backgroundService != null)
          {
             backgroundService.setCallback(null);
          }
       }


      }



   **myService**

公共类MonitorService扩展了Service        {

    private boolean initialized = false;
    private final IBinder mBinder = new LocalBinder();
    private ServiceCallback callback = null;
    private Timer timer = null;
    private final Handler mHandler = new Handler();
    private String foreground = null;
    private ArrayList<HashMap<String,Object>> processList;
    private ArrayList<String> packages;
    private Date split = null;
    // private Date startTime = null;
    public int timeCheckVariable = 0 ;

    public static int SERVICE_PERIOD = 5000; // TODO: customize (this is for scan every 5 seconds)

    private final ProcessList pl = new ProcessList(this)
    {
        @Override
        protected boolean isFilteredByName(String pack)
        {
            // TODO: filter processes by names, return true to skip the process
            // always return false (by default) to monitor all processes
            return false;
        }
    };

    public interface ServiceCallback
    {
        void sendResults(int resultCode, Bundle b);
    }

    public class LocalBinder extends Binder
    {
        MonitorService getService()
        {
            // Return this instance of the service so clients can call public methods
            return MonitorService.this;
        }
    }

    @Override
    public void onCreate()
    {
        super.onCreate();
        initialized = true;
        processList = ((DeviceInsightApp)getApplication()).getProcessList();
        packages = ((DeviceInsightApp)getApplication()).getPackages();
    }

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

    public void setCallback(ServiceCallback callback)
    {
        this.callback = callback;
    }

    // private boolean addToStatistics(String target , Long startTime)
    private boolean addToStatistics(String target )
    {
        boolean changed = false;
        Date now = new Date();
        if(!TextUtils.isEmpty(target))
        {
            if(!target.equals(foreground))
            {
                int i;
                // timeCheckVariable = i ;
                if(foreground != null && split != null)
                {
                    // TODO: calculate time difference from current moment
                    // to the moment when previous foreground process was activated
                    i = packages.indexOf(foreground);
                    timeCheckVariable = i ;
                    long delta = (now.getTime() - split.getTime()) / 1000;
                    Long time = (Long)processList.get(i).get(ProcessList.COLUMN_PROCESS_TIME);
                    if(time != null)
                    {
                        // TODO: add the delta to statistics of 'foreground'
                        time += delta;
                    }
                    else
                    {
                        time = new Long(delta);
                    }

                    processList.get(i).put(ProcessList.COLUMN_PROCESS_TIME, time);
                    //String applicationName = (String)processList.get(i).get(ProcessList.COLUMN_PROCESS_NAME);
                   // DatabaseHandler db = new DatabaseHandler(this);
                  //  int x = time.intValue( );
                   // db.addAppRecord(new AppUsageClass(applicationName  , x));
                   // db.getApplicationCount();
                   // List<AppUsageClass> appUsageClass = db.getAllApplications();
                   // db.getApplicationCount();
                   // for (AppUsageClass cn : appUsageClass) {
                        //String log = "Id: " + cn.getID() + " ,ApplicationName : " + cn.getName() + " ,TimeSpent: " + cn.getTimeSpent();

                       // Log.d("Name: ", log);
                    //}
                }

                //update count of process activation for new 'target'
                i = packages.indexOf(target);
                Integer count = (Integer)processList.get(i).get(ProcessList.COLUMN_PROCESS_COUNT);
                if(count != null) count++;
                else
                {
                    count = new Integer(1);
                }
                processList.get(i).put(ProcessList.COLUMN_PROCESS_COUNT, count);
                foreground = target;
                split = now;
                changed = true;
            }
        }
        //Long checkTimeNow = (Long)processList.get(timeCheckVariable).get(ProcessList.COLUMN_PROCESS_TIME);
        return changed;
    }

    public void start()
    {
        if(timer == null)
        {
            timer = new Timer();
            timer.schedule(new MonitoringTimerTask(), 500, SERVICE_PERIOD);
        }

        // TODO: startForeground(srvcid, createNotification(null));
    }

    public void stop()
    {
        timer.cancel();
        timer.purge();
        timer = null;
    }

    private class MonitoringTimerTask extends TimerTask
    {
        @Override
        public void run()
        {
            fillProcessList();
            ActivityManager activityManager = (ActivityManager)MonitorService.this.getSystemService(ACTIVITY_SERVICE);
            List<ActivityManager.RunningTaskInfo> taskInfo = activityManager.getRunningTasks(1);
            String current = taskInfo.get(0).topActivity.getPackageName(); // gets the application which is in the foreground
            int  i = packages.indexOf(current);
            Long timecheck = (Long)processList.get(i).get(ProcessList.COLUMN_PROCESS_TIME);
            if(addToStatistics(current)&& callback != null)
            {
                final Bundle b = new Bundle();
                // TODO: pass necessary info to UI via bundle
                mHandler.post(new Runnable()
                {
                    public void run()
                    {
                        callback.sendResults(1, b);
                    }
                });
            }
        }
    }
    private void fillProcessList()
    {
        pl.fillProcessList(processList, packages);
    }

1 个答案:

答案 0 :(得分:1)

问题是你没有在.onPause()或.onDestroy()中取消绑定服务,所以如果你的Activity被销毁,连接仍然存在,所以存在泄漏连接。如果您希望服务一直运行,则应该通过.startService()启动它,然后绑定到它。在.onStop()或.onDestroy()中取消绑定该服务