activity
と呼ばれるベースclass
を拡張するLocationAwareActivity
があります。このLocationAwareActivity
activity
は、ロケーションサービスクライアントを作成するだけです。
LocationServices.getFusedLocationProviderClient
およびlistens
から場所の更新。
このアクティビティのソースはこちらhttps://github.com/snijsure/MultiActivity/blob/master/app/src/main/ Java/com/example/subodhnijsure/multiactivity/LocationAwareActivity.Java
そして、アクティビティが破棄されると、removeLocationUpdates
が呼び出されます。私が見つけているのは
removeLocationUpdate
は、常に失敗を返すタスクを返しますactivity
がガベージコレクションされていないことです。 -したがって、LocationAwareActivity
から継承するアクティビティを開始すると、そのアクティビティは常にヒープに留まります。
したがって、問題は、場所の更新の受信を停止して、activity
をガベージコレクションできるようにする正しい方法は何かということです。
このプロジェクトのソース全体はここからアクセスできます- https://github.com/snijsure/MultiActivity
removeLocationUpdatesでは、locationCallbackを渡す必要がありますが、現在の実装は間違っています。
それでも、どこかでメモリリークが発生する可能性があります。アプリに Leakcanary を統合してみてください。参照ツリーが表示され、このメモリリークの原因となっているフィールドまたはリスナーがわかります。あなたは参照することができます ここに私の唯一のブログ投稿の1つ
public void stopLocationUpdates() {
if (locationProviderClient != null) {
try {
final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
if (voidTask.isSuccessful()) {
Log.d(TAG,"StopLocation updates successful! ");
} else {
Log.d(TAG,"StopLocation updates unsuccessful! " + voidTask.toString());
}
}
catch (SecurityException exp) {
Log.d(TAG, " Security exception while removeLocationUpdates");
}
}
}
リポジトリ内のコードを見ると、Activity
のリークを引き起こす可能性のある設計上の問題がいくつか見つかりました。
1)2つの異なるLocationCallbacks
を使用しています。 1つはstartメソッドに、もう1つはstopメソッドにありますが、実際には同じものを使用する必要があります。したがって、一度インスタンス化するだけで十分であり、Task
を削除すると、おそらくLocationCallback
の結果も成功するでしょう。
2)LocationCallback
をAnonymous Class
で2回インスタンス化するため、含まれているクラスを終了しても、内部クラスの非静的参照を保持しているため、Memory Leak
が発生します。あなたはこれについてもっと読むことができます ここ 。
3)私見では、Activity
を抽象化するよりも、ロケーション要求を処理するために別のマネージャークラスを使用することをお勧めします。
それはここに私の...
GpsManager.Java
public class GpsManager extends LocationCallback {
private FusedLocationProviderClient client;
private Callback callback;
public interface Callback {
void onLocationResult(LocationResult locationResult);
}
public boolean start(Context context, Callback callback) {
this.callback = callback;
client = LocationServices.getFusedLocationProviderClient(context);
if (!checkLocationPermission(context)) return false;
client.requestLocationUpdates(getLocationRequest(), this, null);
return true;
}
public void stop() {
client.removeLocationUpdates(this);
}
@Override
public void onLocationResult(LocationResult locationResult) {
callback.onLocationResult(locationResult);
}
private boolean checkLocationPermission(Context context) {
int permissionCheck = ContextCompat.checkSelfPermission(
context, Android.Manifest.permission.ACCESS_FINE_LOCATION);
return permissionCheck == PackageManager.PERMISSION_GRANTED;
}
private LocationRequest getLocationRequest() {
return LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(30_000L)
.setFastestInterval(20_000L);
}
}
Activity
からこれをこのように呼び出します
YourActivity.Java
public class MapsActivity extends AppCompatActivity implements GpsManager.Callback {
private static final int PERMISSION_REQUEST_FINE_LOCATION = 1;
private GpsManager mGpsManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mGpsManager = new GpsManager(getApplicationContext(), this);
// check if user gave permissions, otherwise ask via dialog
if (!checkPermission()) {
getLocationPermissions();
return;
}
mGpsManager.start();
...
}
@Override
protected void onStop() {
super.onStop();
mGpsManager.stop();
}
@Override
public void onLocationResult(LocationResult locationResult) {
// do something with the locationResult
}
// CHECK PERMISSIONS PART
private boolean checkPermission() {
return isGranted(ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION)) &&
isGranted(ActivityCompat.checkSelfPermission(this, ACCESS_COARSE_LOCATION));
}
@TargetApi(Build.VERSION_CODES.M)
private void getLocationPermissions() {
requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSION_REQUEST_FINE_LOCATION);
}
@Override
public void onRequestPermissionsResult(int code, @Nullable String permissions[], @Nullable int[] results) {
switch (code) {
case PERMISSION_REQUEST_FINE_LOCATION:
if (isPermissionGranted(results)) {
getLocationRequest();
}
}
}
private boolean isPermissionGranted(int[] results) {
return results != null && results.length > 0 && isGranted(results[0]);
}
private boolean isGranted(int permission) {
return permission == PackageManager.PERMISSION_GRANTED;
}
}
私はあなたのコードを試していなかったので、これは単なる推測ですが、解決策はとにかくあなたを助けるはずです。私が間違っている場合は私を訂正してください;)
こんにちは@SubodhNijsure以下のコードを確認し、コードに貼り付けて確認してください。
final Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
voidTask.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
Log.e(TAG, "addOnCompleteListener: "+task.isComplete());
}
});
voidTask.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.e(TAG, "addOnSuccessListener: " );
}
});
voidTask.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.e(TAG, "addOnFailureListener: ");
}
});
voidTask.isSuccessful()このリスナーをその時点で正常に動作させると、このメソッドは機能しません。また、前のアクティビティに到達すると、メモリ内ですべてのメモリが解放されることもわかります。
また、アクティビティにリダイレクトする場合は、stopLocationUpdates() onPause()を1回呼び出し、onDestroy()、onStop()などの他のメソッドから削除してください。一度停止するので、複数回呼び出す必要があるのはなぜですか。 。
これがお役に立てば幸いです。
Taskオブジェクトがfalseを返す理由は、stopLocationUpdates
メソッドにあります。ここでも、ローカルの_**LocationCallback**
_参照を作成し、この参照をlocationProviderClient.removeLocationUpdates(cL);
の引数として使用しています。ローカルLocationCallBackがlocationProviderClientに存在することはありません
したがって、別のLocationCallBackオブジェクトを作成する代わりに、startLocationUpdates
メソッドでインスタンス化するのと同じグローバルオブジェクトを渡す必要があります。
コードは次のようになります
_inal Task<Void> voidTask = locationProviderClient.removeLocationUpdates(locationCallback);
_