当用户移出android中的应用程序时,服务中的服务回调将变为null
我创建了一个启动浮动气泡的服务,在这个浮动气泡上,我添加了几个按钮。为了让这些按钮正常工作,我在服务活动中创建了一个界面,并使用服务回调将其与我的主要活动绑定在一起 所以漂浮泡泡的一切都很好,但是一旦用户离开应用程序,漂浮泡泡仍然可以工作,但没有按钮,当用户按下漂浮泡泡应用程序上的任何按钮时,就会在后台崩溃,我试着调试,发现只要用户使用应用程序,接口变量就会变为null 这是我的服务当用户移出android中的应用程序时,服务中的服务回调将变为null,android,interface,android-service,android-service-binding,Android,Interface,Android Service,Android Service Binding,我创建了一个启动浮动气泡的服务,在这个浮动气泡上,我添加了几个按钮。为了让这些按钮正常工作,我在服务活动中创建了一个界面,并使用服务回调将其与我的主要活动绑定在一起 所以漂浮泡泡的一切都很好,但是一旦用户离开应用程序,漂浮泡泡仍然可以工作,但没有按钮,当用户按下漂浮泡泡应用程序上的任何按钮时,就会在后台崩溃,我试着调试,发现只要用户使用应用程序,接口变量就会变为null 这是我的服务 public class FloatingViewService extends Service { p
public class FloatingViewService extends Service {
private WindowManager mWindowManager;
private View mFloatingView;
// Binder given to clients
private final IBinder binder = new LocalBinder();
// Registered callbacks
private ServiceCallbacks serviceCallbacks;
// Class used for the client Binder.
public class LocalBinder extends Binder {
FloatingViewService getService() {
// Return this instance of MyService so clients can call public methods
return FloatingViewService.this;
}
}
public void setCallbacks(ServiceCallbacks callbacks) {
serviceCallbacks = callbacks;
}
public FloatingViewService() {
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
//Inflate the floating view layout we created
mFloatingView = LayoutInflater.from(this).inflate(R.layout.layout_floating_widget, null);
//Add the view to the window.
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
// WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
//Specify the view position
params.gravity = Gravity.TOP | Gravity.LEFT; //Initially view will be added to top-left corner
params.x = 0;
params.y = 100;
//Add the view to the window
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mFloatingView, params);
//….
//….
//The root element of the collapsed view layout
final View collapsedView = mFloatingView.findViewById(R.id.collapse_view);
//The root element of the expanded view layout
final View expandedView = mFloatingView.findViewById(R.id.expanded_container);
//Set the close button
ImageView closeButtonCollapsed = (ImageView) mFloatingView.findViewById(R.id.close_btn);
closeButtonCollapsed.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//close the service and remove the from from the window
stopSelf();
}
});
//Set the view while floating view is expanded.
//Set the start recording button.
ImageView playButton = (ImageView) mFloatingView.findViewById(R.id.startRecording);
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Toast.makeText(FloatingViewService.this, "Recording started", Toast.LENGTH_LONG).show();
//serviceCallbacks.onClick(1);
}
});
//stop recording.
ImageView nextButton = (ImageView) mFloatingView.findViewById(R.id.stopRecording);
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Toast.makeText(FloatingViewService.this, "recording stoped.", Toast.LENGTH_LONG).show();
serviceCallbacks.onClick(2);
}
});
//Set the close button
ImageView closeButton = (ImageView) mFloatingView.findViewById(R.id.close_button);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
collapsedView.setVisibility(View.VISIBLE);
expandedView.setVisibility(View.GONE);
}
});
//Drag and move floating view using user's touch action.
mFloatingView.findViewById(R.id.root_container).setOnTouchListener(new View.OnTouchListener() {
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//remember the initial position.
initialX = params.x;
initialY = params.y;
//get the touch location
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
return true;
case MotionEvent.ACTION_UP:
int Xdiff = (int) (event.getRawX() - initialTouchX);
int Ydiff = (int) (event.getRawY() - initialTouchY);
//The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little while clicking.
//So that is click event.
if (Xdiff < 10 && Ydiff < 10) {
if (isViewCollapsed()) {
//When user clicks on the image view of the collapsed layout,
//visibility of the collapsed layout will be changed to "View.GONE"
//and expanded view will become visible.
collapsedView.setVisibility(View.GONE);
expandedView.setVisibility(View.VISIBLE);
}
}
return true;
case MotionEvent.ACTION_MOVE:
//Calculate the X and Y coordinates of the view.
params.x = initialX + (int) (event.getRawX() - initialTouchX);
params.y = initialY + (int) (event.getRawY() - initialTouchY);
//Update the layout with new X & Y coordinate
mWindowManager.updateViewLayout(mFloatingView, params);
return true;
}
return false;
}
});
}
private boolean isViewCollapsed() {
return mFloatingView == null || mFloatingView.findViewById(R.id.collapse_view).getVisibility() == View.VISIBLE;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mFloatingView != null) mWindowManager.removeView(mFloatingView);
}
public interface ServiceCallbacks {
void onClick(int type);
}
}
public类FloatingViewService扩展服务{
专用窗口管理器mWindowManager;
私有视图mFloatingView;
//给客户的活页夹
专用最终IBinder绑定器=新的LocalBinder();
//注册回调
私有服务回调服务回调;
//用于客户端绑定器的类。
公共类LocalBinder扩展了Binder{
FloatingViewService getService(){
//返回此MyService实例,以便客户端可以调用公共方法
返回FloatingViewService.this;
}
}
公共void setCallbacks(ServiceCallbacks callbacks){
serviceCallbacks=回调;
}
公共浮动视图服务(){
}
@凌驾
公共IBinder onBind(意向){
返回活页夹;
}
@凌驾
public void onCreate(){
super.onCreate();
//膨胀我们创建的浮动视图布局
mFloatingView=LayoutInflater.from(this).充气(R.layout.layout\u floating\u小部件,null);
//将视图添加到窗口中。
final WindowManager.LayoutParams params=新建WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_内容,
WindowManager.LayoutParams.WRAP_内容,
//WindowManager.LayoutParams.TYPE_电话,
WindowManager.LayoutParams.TYPE\u应用程序\u覆盖,
WindowManager.LayoutParams.FLAG\u不可聚焦,
像素格式(半透明);
//指定视图位置
params.gravity=gravity.TOP | gravity.LEFT;//最初视图将添加到左上角
参数x=0;
参数y=100;
//将视图添加到窗口中
mWindowManager=(窗口管理器)getSystemService(窗口服务);
mWindowManager.addView(mFloatingView,params);
//….
//….
//折叠视图布局的根元素
最终视图collapsedView=mFloatingView.findViewById(R.id.collapsedView);
//展开视图布局的根元素
最终视图expandedView=mFloatingView.findViewById(R.id.expanded_容器);
//设置关闭按钮
ImageView closeButtonCollapsed=(ImageView)mFloatingView.findViewById(R.id.close_btn);
closeButtonCollapsed.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图){
//关闭服务并从窗口中卸下
stopSelf();
}
});
//在展开浮动视图时设置视图。
//设置开始录制按钮。
ImageView播放按钮=(ImageView)mFloatingView.findViewById(R.id.startRecording);
playButton.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图v){
//Toast.makeText(FloatingViewService.this,“录制已开始”,Toast.LENGTH_LONG.show();
//serviceCallbacks.onClick(1);
}
});
//停止录音。
ImageView下一个按钮=(ImageView)mFloatingView.findViewById(R.id.stopRecording);
setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图v){
//Toast.makeText(FloatingViewService.this,“录制已停止。”,Toast.LENGTH_LONG.show();
serviceCallbacks.onClick(2);
}
});
//设置关闭按钮
ImageView关闭按钮=(ImageView)mFloatingView.findViewById(R.id.close_按钮);
closeButton.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图){
collapsedView.setVisibility(View.VISIBLE);
expandedView.setVisibility(View.GONE);
}
});
//使用用户的触摸操作拖动和移动浮动视图。
mFloatingView.findViewById(R.id.root_容器).setOnTouchListener(新视图.OnTouchListener(){
私有int initialX;
私有int初始值;
私有浮点数;
私家侦探敏感;
@凌驾
公共布尔onTouch(视图v,运动事件){
开关(event.getAction()){
case MotionEvent.ACTION\u DOWN:
//记住初始位置。
initialX=参数x;
初始值y=参数y;
//获取触摸位置
initialTouchX=event.getRawX();
initialTouchY=event.getRawY();
返回true;
case MotionEvent.ACTION\u UP:
int Xdiff=(int)(event.getRawX()-initialTouchX);
int-Ydiff=(int)(event.getRawY()-initialTouchY);
//检查Xdiff=Build.VERSION_CODES.M&&!Settings.canDrawOverlays(此)){
//如果提取权限不可用,请打开设置屏幕
//授予许可。
意向意向=新意向(设置、操作、管理、覆盖、权限、,
parse(“包:”+ge
public class MainActivity extends AppCompatActivity implements View.OnClickListener, HBRecorderListener, FloatingViewService.ServiceCallbacks {
private HBRecorder recorder;
private static final int PERMISSION_REQ_ID_RECORD_AUDIO = 22;
private static final int PERMISSION_REQ_ID_WRITE_EXTERNAL_STORAGE = PERMISSION_REQ_ID_RECORD_AUDIO + 1;
private static final int CODE_DRAW_OVER_OTHER_APP_PERMISSION = 2084;
private boolean hasPermissions = false;
private FloatingViewService myService;
private boolean bound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkFloatingPermission();
recorder = new HBRecorder(this, this);
findViewById(R.id.startR).setOnClickListener(this);
findViewById(R.id.stopR).setOnClickListener(this);
}
private void checkFloatingPermission() {
//Check if the application has draw over other apps permission or not?
//This permission is by default available for API<23. But for API > 23
//you have to ask for the permission in runtime.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
//If the draw over permission is not available open the settings screen
//to grant the permission.
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, CODE_DRAW_OVER_OTHER_APP_PERMISSION);
} else {
Toast.makeText(this, "floting permission already given", Toast.LENGTH_SHORT).show();
initializeView();
}
}
@Override
protected void onStart() {
super.onStart();
// bind to Service
Intent intent = new Intent(this, FloatingViewService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
/**
* Callbacks for service binding, passed to bindService()
*/
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// cast the IBinder and get MyService instance
FloatingViewService.LocalBinder binder = (FloatingViewService.LocalBinder) service;
myService = binder.getService();
bound = true;
myService.setCallbacks(MainActivity.this); // register
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
bound = false;
}
};
@Override
protected void onStop() {
super.onStop();
// Unbind from service
if (bound) {
myService.setCallbacks(null); // unregister
unbindService(serviceConnection);
bound = false;
}
}
private void initializeView() {
startService(new Intent(MainActivity.this, FloatingViewService.class));
}
@Override
public void onClick(View view) {
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO, PERMISSION_REQ_ID_RECORD_AUDIO) && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSION_REQ_ID_WRITE_EXTERNAL_STORAGE)) {
hasPermissions = true;
}
if (view.getId() == R.id.startR && hasPermissions) {
startRecordingScreen();
} else if (view.getId() == R.id.stopR && hasPermissions) {
recorder.stopScreenRecording();
}
}
private boolean checkSelfPermission(String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQ_ID_RECORD_AUDIO:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSION_REQ_ID_WRITE_EXTERNAL_STORAGE);
} else {
hasPermissions = false;
}
break;
case PERMISSION_REQ_ID_WRITE_EXTERNAL_STORAGE:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
hasPermissions = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startRecordingScreen();
}
} else {
hasPermissions = false;
}
break;
default:
break;
}
}
public void startRecordingScreen() {
if (recorder.isBusyRecording()) {
recorder.stopScreenRecording();
}
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
Intent permissionIntent = mediaProjectionManager != null ? mediaProjectionManager.createScreenCaptureIntent() : null;
startActivityForResult(permissionIntent, 101);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CODE_DRAW_OVER_OTHER_APP_PERMISSION) {
//Check if the permission is granted or not.
if (resultCode == RESULT_OK) {
initializeView();
} else { //Permission is not available
Toast.makeText(this,
"Draw over other app permission not available. Closing the application",
Toast.LENGTH_SHORT).show();
finish();
}
}
if (requestCode == 101) {
if (resultCode == RESULT_OK) {
recorder.startScreenRecording(data, resultCode, this);
}
}
}
@Override
public void HBRecorderOnStart() {
Toast.makeText(this, "recording start", Toast.LENGTH_SHORT).show();
}
@Override
public void HBRecorderOnComplete() {
Toast.makeText(this, "file saved at: " + recorder.getFilePath(), Toast.LENGTH_LONG).show();
}
@Override
public void HBRecorderOnError(int errorCode, String reason) {
Toast.makeText(this, "recording error", Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(int type) {
Toast.makeText(myService, "workinggggggg", Toast.LENGTH_SHORT).show();
if (type == 1) {
if (checkSelfPermission(Manifest.permission.RECORD_AUDIO, PERMISSION_REQ_ID_RECORD_AUDIO) && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSION_REQ_ID_WRITE_EXTERNAL_STORAGE)) {
hasPermissions = true;
}
if (hasPermissions) {
startRecordingScreen();
}
} else
recorder.stopScreenRecording();
}
}