2017-03-20 1 views
0

나는 Activity A, Service S 및 BroadcastReceiver BR이 포함 된 응용 프로그램을 가지고 있습니다. 응용 프로그램에서 사용자가 전화를 잠금 해제 할 때들을 수 있습니다. 이것은 현재 A가 S를 시작하고 그것에 바인딩함으로써 달성됩니다. S가 시작되고 BR을 등록하여 "android.intent.action.USER_PRESENT"를 청취합니다."USER_PRESENT"에 대한 BroadcastReceiver 누수 메모리

응용 프로그램은 이론적으로 전화 잠금 해제를 백그라운드에서 무기한 수신 대기 할 수 있어야합니다. 내 응용 프로그램은 목적을 완료하지만 안드로이드 모니터에서 메모리 사용이 꾸준히 증가하는 것을 보았습니다. 그리고 각 잠금 해제마다 (onReceive가 호출 될 때마다 (?)) 약 0,033MB가 증가합니다.

다음은 코드입니다.

활동 :

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()); 
    } 
} 

UnlockStatus :

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); 
    } 
} 
+0

onPause에서 등록 취소() 공공 무효 onPause() {unregisterReceiver (userPresentReceiver); } – Rajasekhar

+0

활동이 삭제 된 후에도 사용자가 전화를 잠금 해제 할 때 응용 프로그램에서 확인하도록하고 싶습니다. 그래서 백그라운드에서 실행되는 서비스에 수신기를 등록했습니다. – HSOdegard

답변

0

해결책을 찾아주세요

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(); 
    } 
}}