BroadcastReceiver для USER_PRESENT утечки памяти

У меня есть приложение, содержащее Activity A, Service S и BroadcastReceiver BR. Я хочу, чтобы приложение слушало, когда пользователь разблокирует телефон. В настоящее время это достигается за счет того, что A запускает S и привязывается к нему. S запустится и зарегистрирует BR для прослушивания «android.intent.action.USER_PRESENT».

Теоретически приложение должно иметь возможность бесконечно прослушивать разблокировку телефона в фоновом режиме. Мое приложение выполняет свою задачу, но я вижу в мониторе Android, что использование памяти неуклонно увеличивается и будет увеличиваться примерно на 0,033 МБ для каждой разблокировки (каждый раз, когда вызывается onReceive (?)).

Ниже приведен код.

Мероприятия:

public class MainActivity extends Activity implements BackgroundService.ServiceCallbacks
{
    private TextView lastUnlock;
    private boolean isBound = false;
    private BackgroundService backgroundService;
    private ServiceConnection serviceConnection = new ServiceConnection()
    {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            BackgroundService.LocalBinder binder = (BackgroundService.LocalBinder) service;
            backgroundService = binder.getServiceInstance();
            backgroundService.registerActivity(MainActivity.this);
        }
        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            isBound = false;
            backgroundService = null;
        }
    };

    /** Activity is created, start service and bind to it **/
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lastUnlock = (TextView) findViewById(R.id.lastUnlock_TW);

        Intent serviceIntent = new Intent(this, BackgroundService.class);
        startService(serviceIntent);

        bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE);
        isBound = true;
    }

    /** Activity is destroyed, it should unbind from the service **/
    @Override
    protected void onDestroy()
    {
        super.onDestroy();

        if (isBound)
        {
            backgroundService.unregisterActivity();
            unbindService(serviceConnection);
            isBound = false;
        }
    }

    /** The service can call this method to update the lastUnlock TextView **/
    @Override
    public void updateClient(String data)
    {
        lastUnlock.setText(data);
    }
}

Обслуживание:

public class BackgroundService extends Service
{
    ServiceCallbacks activity;
    private final IBinder LOCAL_BINDER = new LocalBinder();
    private UserPresentReceiver userPresentReceiver;
    SharedPreferences sharedPreferences;

    /** The service is created, receivers are registered here **/
    @Override
    public void onCreate()
    {
        super.onCreate();
        userPresentReceiver = new UserPresentReceiver();
        registerReceiver(userPresentReceiver, new IntentFilter("android.intent.action.USER_PRESENT"));

        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    }

    /** An activity called startService() or the process was killed, returning START_STICKY
     ** which restarts the service and this method is called **/
    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        return START_STICKY;
    }

    /** An activity just bound to the service **/
    @Override
    public IBinder onBind(Intent intent)
    {
        return LOCAL_BINDER;
    }

    /** Service is destroyed, unregister the receivers **/
    @Override
    public void onDestroy()
    {
        super.onDestroy();
        unregisterReceiver(userPresentReceiver);
    }

    /**  **/
    public class LocalBinder extends Binder
    {
        public BackgroundService getServiceInstance()
        {
            return BackgroundService.this;
        }
    }

    /** Update the activity if it is connected, and save the unlockStatus in the preferences **/
    public void updateActivity(String unlockStatus)
    {
        if (activity != null)
        {
            this.activity.updateClient(unlockStatus);
        }

        SharedPreferences.Editor spEditor = sharedPreferences.edit();
        spEditor.putString("saved_last_unlock", unlockStatus);
        spEditor.apply();
    }

    /** Methods an activity can call to register or unregister itself to the service **/
    public void registerActivity(Activity activity)
    {
        this.activity = (ServiceCallbacks) activity;

        // If the last unlock is saved in the preferences, retrieve it from there
        String savedLastUnlock = sharedPreferences.getString("saved_last_unlock", null);
        if (savedLastUnlock != null)
        {
            this.activity.updateClient(savedLastUnlock);
        }
    }
    public void unregisterActivity()
    {
        activity = null;
    }

    /** An activity has to implement this interface so that the service can send commands to it **/
    public interface ServiceCallbacks
    {
        void updateClient(String data);
    }
}

Широковещательный приемник:

public class UserPresentReceiver extends BroadcastReceiver
{
    private final String TAG = "UserPresentReceiver";
    UnlockStatus unlockStatus;

    public UserPresentReceiver()
    {
        unlockStatus = new UnlockStatus();
    }

    @Override
    public void onReceive(Context context, Intent intent)
    {
        unlockStatus.setStatus(new Date());

        BackgroundService service = (BackgroundService) context;
        service.updateActivity(unlockStatus.getStatus());
    }
}

Статус разблокировки:

public class UnlockStatus
{
    private Calendar calendar;
    private final SimpleDateFormat SDF = new SimpleDateFormat("dd.MM.yyyy' kl. 'HH:mm:ss");
    private boolean unlockRegistered = false;

    public UnlockStatus()
    {
        calendar = Calendar.getInstance();
    }


    public String getStatus()
    {
        if (unlockRegistered)
            return SDF.format(calendar.getTime());
        else
            return null;
    }


    public void setStatus(Date date)
    {
        unlockRegistered = true;
        calendar.setTime(date);
    }
}

person HSOdegard    schedule 20.03.2017    source источник
comment
Отменить регистрацию в onPause() public void onPause() { unregisterReceiver(userPresentReceiver); }   -  person Rajasekhar    schedule 20.03.2017
comment
Я хочу, чтобы приложение проверяло, когда пользователь разблокирует телефон, даже после уничтожения активности. Вот почему я зарегистрировал приемник в службе, работающей в фоновом режиме.   -  person HSOdegard    schedule 20.03.2017


Ответы (1)


Пожалуйста, найдите решение

public class MyApplication extends Application implements HM_Constants, Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
public static String stateOfLifeCycle = "";
public static boolean wasInBackground = false;
private static HydratemateApplication mInstance;
private static String TAG = HydratemateApplication.class.getName();
boolean status;
ScreenOffReceiver screenOffReceiver = new ScreenOffReceiver();

public static synchronized HydratemateApplication getInstance() {
    return mInstance;
}

@Override
public void onCreate() {
    super.onCreate();
    mInstance = this;
    registerActivityLifecycleCallbacks(this);
    registerReceiver(screenOffReceiver, new IntentFilter("android.intent.action.SCREEN_OFF"));
    // new HM_PrefsManager(mInstance).save(Prefs_Keys.SERVICE_THREAD_STOP,"NO");
}

@Override
public void onActivityCreated(Activity activity, Bundle arg1) {
    //   Log.d(TAG, "onActivityCreated " + activity.getLocalClassName());
    wasInBackground = false;
    status = false;
    stateOfLifeCycle = "Create";
}

@Override
public void onActivityStarted(Activity activity) {
    //  Log.d(TAG, "onActivityStarted " + activity.getLocalClassName());
    stateOfLifeCycle = "Start";
}

@Override
public void onActivityResumed(Activity activity) {


    Log.d(TAG, "onActivityResumed " + activity.getLocalClassName());
    stateOfLifeCycle = "Resume";

    try {
        Intent service = new Intent(getApplicationContext(), VolumeService.class);
        stopService(service);
    } catch (Exception e) {
        e.printStackTrace();
    }
    try {
        if (BatteryHealthActivity.mBluetoothLeForegroundService != null && status) {
            //BatteryHealthActivity.mBluetoothLeForegroundService.indicateCharacteristic(UUID.fromString(GattAttributes.BATTERY_LEVEL_SERVICE_UUID), UUID.fromString(GattAttributes.BATTERY_LEVEL_CHARACTERSTIC_UUID), true);
            status = false;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

@Override
public void onActivityPaused(Activity activity) {
    //  Log.d(TAG, "onActivityPaused " + activity.getLocalClassName());
    stateOfLifeCycle = "Pause";
}

@Override
public void onActivityStopped(Activity activity) {
    //   Log.d(TAG, "onActivityStopped " + activity.getLocalClassName());
    stateOfLifeCycle = "Stop";
}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle arg1) {
    //Log.d(TAG, "onActivitySaveInstanceState " + activity.getLocalClassName());
}

@Override
public void onActivityDestroyed(Activity activity) {
    // Log.d(TAG, "onActivityDestroyed " + activity.getLocalClassName());
    Log.d("iam", "calling");
    wasInBackground = false;
    stateOfLifeCycle = "Destroy";

}

@Override
public void onTrimMemory(int level) {
    if (stateOfLifeCycle.equals("Stop")) {
        wasInBackground = true;
    }
    super.onTrimMemory(level);
    Log.d(TAG, "onTrimMemory " + level);
    onBackground();
}

public void onBackground(){
    if (!isMyServiceRunning(VolumeService.class)) {
        try {
            status = true;
            if (BatteryHealthActivity.mBluetoothLeForegroundService != null) {
                BatteryHealthActivity.mBluetoothLeForegroundService.indicateCharacteristic(UUID.fromString(GattAttributes.BATTERY_LEVEL_SERVICE_UUID), UUID.fromString(GattAttributes.BATTERY_LEVEL_CHARACTERSTIC_UUID), false);
            }
            new ForegroundCheckTask().execute(mInstance).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

private boolean isMyServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (serviceClass.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

class ScreenOffReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        wasInBackground = true;
        onBackground();
    }
}}
person Rajasekhar    schedule 20.03.2017