当用户移出android中的应用程序时,服务中的服务回调将变为null

当用户移出android中的应用程序时,服务中的服务回调将变为null,android,interface,android-service,android-service-binding,Android,Interface,Android Service,Android Service Binding,我创建了一个启动浮动气泡的服务,在这个浮动气泡上,我添加了几个按钮。为了让这些按钮正常工作,我在服务活动中创建了一个界面,并使用服务回调将其与我的主要活动绑定在一起 所以漂浮泡泡的一切都很好,但是一旦用户离开应用程序,漂浮泡泡仍然可以工作,但没有按钮,当用户按下漂浮泡泡应用程序上的任何按钮时,就会在后台崩溃,我试着调试,发现只要用户使用应用程序,接口变量就会变为null 这是我的服务 public class FloatingViewService extends Service { p

我创建了一个启动浮动气泡的服务,在这个浮动气泡上,我添加了几个按钮。为了让这些按钮正常工作,我在服务活动中创建了一个界面,并使用服务回调将其与我的主要活动绑定在一起

所以漂浮泡泡的一切都很好,但是一旦用户离开应用程序,漂浮泡泡仍然可以工作,但没有按钮,当用户按下漂浮泡泡应用程序上的任何按钮时,就会在后台崩溃,我试着调试,发现只要用户使用应用程序,接口变量就会变为null

这是我的服务

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