启动新活动后 Android 服务连接泄漏
我试图找出为什么我的服务从我的应用程序中泄漏。
我收到的官方错误是该服务不再注册。
这是有效的: 我创建了一个服务,该服务创建一个侦听器,当触发侦听器时,服务集会启动另一个活动。新的活动开始并完成它的任务。
问题: 当我回到主屏幕时,我可以选择关闭服务,我收到了我之前所说的错误,这导致了 IllegalArgumentException(当我尝试解除绑定未注册的服务时)。
任何帮助将不胜感激。这是我的服务的代码。这就是我所包含的全部内容,因为这似乎是问题所在,但如果您需要更多内容,请告诉我。
预先感谢,这是代码。
import java.lang.ref.WeakReference;
import java.util.List;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class AccelService extends Service
{
public static boolean listening = false;
public boolean callMade = false;
private static Sensor sensor;
private static SensorManager ASensorManager;
private SensorEventListener EventListener =
new SensorEventListener() {
private float x = 0;
private float y = 0;
private float z = 0;
private double max = 0;
private double force = 0;
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
public void onSensorChanged(SensorEvent event)
{
x = event.values[0];
y = event.values[1];
z = event.values[2];
force = Math.sqrt(x*x+y*y+z*z);
Log.i("LocalService", "Event happened: " + force);
if (force > Main.dropValue)
{
onDrop(force);
}
}
};
public void startListener()
{
ASensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
List<Sensor> sensors = ASensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (sensors.size() > 0)
{
sensor = sensors.get(0);
listening = ASensorManager.registerListener(accelEventListener, sensor, SensorManager.SENSOR_DELAY_GAME);
}
}
public class AccelBinder<S> extends Binder
{
private WeakReference<S> mService;
public AccelBinder (S service)
{
mService = new WeakReference<S>(service);
}
public S getService()
{
return mService.get();
}
}
public IBinder mBinder;
@Override
public void onCreate()
{
startListener();
mBinder = new AccelBinder<AccelService>(this);
}
public boolean isListening()
{
return listening;
}
/*@Override
public void onStart(Intent intent, int startId)
{
Log.i("LocalService", "Received start id " + startId + ": " + intent);
}*/
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.i("LocalService", "Received start id " + startId + ": " + intent);
return AccelService.START_STICKY;
}
@Override
public void onDestroy()
{
if (listening)
stopListening();
mBinder = null;
super.onDestroy();
}
public void onDrop(double force)
{
if (!callMade)
{
Toast.makeText(this, "Phone dropped: " + force, 5000).show();
Intent i = new Intent(this,Next.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
callMade = true;
//stopListening();
//onDestroy();
//SafetyNet.ctxt.unbindService(SafetyNet.AccelWatch);
this.startActivity(i);
}
}
public void stopListening()
{
listening = false;
try {
if (ASensorManager != null && accelEventListener != null)
{
ASensorManager.unregisterListener(accelEventListener);
}
} catch (Exception e) {}
}
@Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
}
I am trying to figure out why my service is leaking from my application.
The official error I am getting is that the Service is not registered any longer.
Here's what works:
I create a service which creates a listener, when the listener is triggered the service sets of an intent to start another activity. The new activity begins and does its thing.
The problem:
When I get back to a main screen which gives me the option to turn off the service, I get the error which I stated previously which causes an IllegalArgumentException (when I try to unbind the service which is not registered).
Any help would be greatly appreciated. Here is the code for my service. It is all I've included because this seems to be where the problem is, but if you need any more let me know.
Thanks in advance, here is the code.
import java.lang.ref.WeakReference;
import java.util.List;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class AccelService extends Service
{
public static boolean listening = false;
public boolean callMade = false;
private static Sensor sensor;
private static SensorManager ASensorManager;
private SensorEventListener EventListener =
new SensorEventListener() {
private float x = 0;
private float y = 0;
private float z = 0;
private double max = 0;
private double force = 0;
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
public void onSensorChanged(SensorEvent event)
{
x = event.values[0];
y = event.values[1];
z = event.values[2];
force = Math.sqrt(x*x+y*y+z*z);
Log.i("LocalService", "Event happened: " + force);
if (force > Main.dropValue)
{
onDrop(force);
}
}
};
public void startListener()
{
ASensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
List<Sensor> sensors = ASensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (sensors.size() > 0)
{
sensor = sensors.get(0);
listening = ASensorManager.registerListener(accelEventListener, sensor, SensorManager.SENSOR_DELAY_GAME);
}
}
public class AccelBinder<S> extends Binder
{
private WeakReference<S> mService;
public AccelBinder (S service)
{
mService = new WeakReference<S>(service);
}
public S getService()
{
return mService.get();
}
}
public IBinder mBinder;
@Override
public void onCreate()
{
startListener();
mBinder = new AccelBinder<AccelService>(this);
}
public boolean isListening()
{
return listening;
}
/*@Override
public void onStart(Intent intent, int startId)
{
Log.i("LocalService", "Received start id " + startId + ": " + intent);
}*/
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.i("LocalService", "Received start id " + startId + ": " + intent);
return AccelService.START_STICKY;
}
@Override
public void onDestroy()
{
if (listening)
stopListening();
mBinder = null;
super.onDestroy();
}
public void onDrop(double force)
{
if (!callMade)
{
Toast.makeText(this, "Phone dropped: " + force, 5000).show();
Intent i = new Intent(this,Next.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
callMade = true;
//stopListening();
//onDestroy();
//SafetyNet.ctxt.unbindService(SafetyNet.AccelWatch);
this.startActivity(i);
}
}
public void stopListening()
{
listening = false;
try {
if (ASensorManager != null && accelEventListener != null)
{
ASensorManager.unregisterListener(accelEventListener);
}
} catch (Exception e) {}
}
@Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我对传感器了解不多,但你们的服务看起来不错。
如果 AccelBinder 是您服务的内部类,请将其设置为静态内部类,或者像我通常所做的那样,完全是一个单独的类。静态内部类没有对外部类的引用。请记住,您将泄漏您的 Binder。如果您的 Binder 是非静态内部类,它会引用您的 Service,因此也会泄漏。
我猜测 - 就像真正疯狂的猜测 - 在没有任何代码的情况下,您的 Activity 生命周期的管理以及您处理 Binder 对象的方式存在问题。
要记住的事情......
不要保留对 Binder 对象的静态引用 - 它们是一次性的 - 每次绑定时都获取一个新的。
保持您的绑定与您的活动生命周期对称。如果您在 onCreate() 中绑定,在 onDestroy() 中取消绑定(或 onPause if isFinishing() )等。如果您不明白带有传感器的手机的物理旋转会破坏您的 Activity 并从头开始重新创建它,那么这一点尤其重要。
您似乎太喜欢“静态”类变量了。在 Android 中,静态的东西往往会导致内存泄漏——如果你泄漏的东西有上下文——事情就会变得很糟糕。如果您想在同一类的实例之间保留状态,请考虑使用首选项。
例如,
在使用之间将其扔掉。
尤其要确保您没有在活动中保留对服务的静态引用。就 Android 的本质而言,服务是单例的,如果它仍在运行,则每次绑定时都会获得相同的服务。预计您的服务会在某个时间点被操作系统终止。编写您的服务,以便在重新启动时它可以完成其工作。
一天的猜测就够了。
I don't know much about Sensors, but your Service is looking pretty good.
IF AccelBinder is an inner class of your service make it a static inner class or, as I generally do, a separate class altogether. Static inner classes don't have a reference to the outer class. Remember you WILL leak your Binder. If your Binder is a non-static inner class, it has a reference to your Service so that will leak as well.
I am guessing - like really wildly guessing - in the absence of any code that there is something wrong with the management of your Activity life-cycle and how you handle your Binder objects.
Things to keep in mind....
Don't keep a static reference to your Binder object - they are disposable - get a new one each time you bind.
Keep your Binding symmetrical with regards to your Activity life-cycle. If you bind in onCreate(), unbind in onDestroy() ( or onPause if isFinishing() ) etc. This is particularly important if you don't understand that a physical rotation of a phone with Sensor destroys your Activity the recreates it from scratch.
You seem altogether too fond of "static" class variables. In Android static things tend to lead to memory leaks - and if what you leak has a Context - things get nasty. If you want to keep state between instances of the same class, consider using Preferences instead.
For example,
Throw these away between uses.
Make sure you especially are not keeping a static reference to your Service in your Activity. Services are singletons by the very nature of the Android, if it is still running you will get the same Service each time you bind. Count on your Service being killed by the OS at some point in time. Write your Service so that it does it's job if it is restarted afresh.
That's enough guessing for one day.