0

I have a working app using threads in fragments, the thing is I need to change the layout. It's not gonna be a Fragment anymore but a standard Activity.

My big problem is that I don't know exactly where to place what's in "onViewCreated" and "onCreateView" so it's crashing when I call "connect to device" which's placed on "onCreateView". Probably because it's too early or something.

@Nullable
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){
    View view;
    view = inflater.inflate(R.layout.fragment_home_2, container, false);

    //Linking layout views
    connectToDevice = view.findViewById(R.id.connect_to_device);
    startRecording = view.findViewById(R.id.start_recording);
    stopRecording = view.findViewById(R.id.stop_recording);
    connectedToDevice = view.findViewById(R.id.connected_to_device);
    mAdapter = new DeviceListAdapter(container.getContext(), activeDevices);
    imgEkoDevice = view.findViewById(R.id.img_ekodevice);

    //Enable bluetooth and start scanning thread
    BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
    if (btAdapter != null && !btAdapter.isEnabled()) {
        btAdapter.enable();
    }

    //Layout setup
    connectedToDevice.setText(getResources().getString(R.string.welcome_to_scopefy));

    //Thread setup to search for device
    scanningThread = new Thread(){
        @Override
        public void run(){
            Log.i(AppConstants.TAG, "scanning...");
            LibCore.getInstance(ConnectDeviceActivity.this).startScanningForDevices(new EkoDeviceScan() {
                @Override
                public void foundDevice(BLEDevice bleDevice) {
                    //Log.i(AppPreferences.log, "foundDevice: " + bleDevice.toString());
                    if(activeDevices.isEmpty()){
                        //Adding first device to list
                        activeDevices.add(bleDevice);
                    }
                    else{
                        int i = 0;
                        newDevice = true;
                        //Checks if its already on the list
                        while(i < activeDevices.size() && newDevice){
                            if(activeDevices.get(i).getAddress().equals(bleDevice.getAddress())){
                                newDevice = false;
                            }
                            i++;
                        }
                        if(newDevice){
                            activeDevices.add(bleDevice);
                        }
                    }

                    //Show list and dismiss search dialog
                    if(connect){
                        showDeviceListDialog();
                        if(emptyListDialog != null){
                            emptyListDialog.dismiss();
                        }
                        connect = false;
                    }
                }
            });
        }
    };

    LocalBroadcastManager.getInstance(ConnectDeviceActivity.this).registerReceiver(mDeviceReceiver, new IntentFilter(Parameters.DEVICE_REFRESH_DATA));

    //Starting scanning background to speed up
    if(LibCore.getInstance(ConnectDeviceActivity.this).getCurrentConnectedDevice() == null){
        scanningThread.start();
        LibCore.getInstance(ConnectDeviceActivity.this).setFiltering(true);
        connected = false;
    } else {
        mEkoDevice = LibCore.getInstance(ConnectDeviceActivity.this).getCurrentConnectedDevice();
        connected = true;
    }

    //Broadcast receiver for patientId
    LocalBroadcastManager.getInstance(ConnectDeviceActivity.this).registerReceiver(mPatientReceiver, new IntentFilter(Parameters.PATIENT_ID));

    //Listeners and receivers for device connection
    LibCore.getInstance(ConnectDeviceActivity.this).setBatteryListener(new EkoDeviceBatteryLevel() {
        @Override
        public void deviceUpdatedBatteryLevel(float v) {
            Log.i("HUEBR123", "updateou bat");
            LocalBroadcastManager.getInstance(ConnectDeviceActivity.this).sendBroadcast(new Intent(Parameters.DEVICE_REFRESH_DATA).putExtra(Parameters.DEVICE_UPDATED_BATTERY_LEVEL, v));
        }
    });

    LibCore.getInstance(ConnectDeviceActivity.this).setVolumeListener(new EkoDeviceVolume() {
        @Override
        public void deviceUpdatedVolumeLevel(int i) {
            Log.i("HUEBR123", "updateou vol");
            LocalBroadcastManager.getInstance(ConnectDeviceActivity.this).sendBroadcast(new Intent(Parameters.DEVICE_REFRESH_DATA).putExtra(Parameters.DEVICE_UPDATED_VOLUME_LEVEL, i));
        }
    });



    //Settings
    userSettingsDAO = new UserSettingsDAO(ConnectDeviceActivity.this);
    settings = userSettingsDAO.getUserSettings();

    //Button's listeners
    connectToDevice.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            connect = true;
            scanningThread.run();
            showDeviceListEmptyDialog();
        }
    });

    startRecording.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.i(AppConstants.TAG, "starting recording...");
            stopped = false;
            startRecording();
            //startPlayRecordThroughEko();
            startRecording.setVisibility(View.GONE);
            stopRecording.setVisibility(View.VISIBLE);
            recording = true;

            settings = userSettingsDAO.getUserSettings();
            settings.getRecordingLength();

            Timer timer = new Timer();
            TimerTask task  = new StopRecordingTask();
            timer.schedule(task, settings.getRecordingLength() * 1000);
            Log.i(AppConstants.TAG, "#timer starting for " + settings.getRecordingLength() + " seconds");
        }
    });

    stopRecording.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            try {
                mEkoOutputAudioByteListener = null;
                mAudioFileOutputStream.close();
                writeWAVHeader(mCachedAudioRecordingFile, 4000);
                //writeWAVHeader(mCachedECGRecordingFile, 500);
                stopOutputtingAudioDataPoints();
            } catch (Exception e) {
                e.printStackTrace();
            }
            startRecording.setVisibility(View.VISIBLE);
            stopRecording.setVisibility(View.GONE);

            recording = false;

            short[] output;
            output = new short[outData.size() * 32];
            for(int i=0; i<outData.size(); i++){
                for(int j=0; j<32; j++){
                    output[i] = outData.get(i)[j];
                }
            }

            Intent intent = new Intent(ConnectDeviceActivity.this, AuscultationActivity.class);
            intent.putExtra("output", output);
            intent.putExtra("patient-id", patientId);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            Log.i(AppConstants.TAG, "OUPUTLEN: " + output.length);
            if(!stopped) {
                stopped = true;
                startActivity(intent);
            }
        }
    });

    return view;
}

//This overridden method makes DynamicWaveformViews avoid crashing
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    dynamicWaveformView = (DynamicWaveformView) view.findViewById(R.id.dynamic_waveform_view);
    dynamicWaveformView.init();

    mAudioThread = new HandlerThread("AudioThread");
    mAudioThread.start();
    mAudioHandler = new Handler(mAudioThread.getLooper());

    //updateView again for consistency (mDeviceBroadcast may be too much but still works)
    updateView(connected);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mEkoDevice = new EkoDevice("DUMMY_DEVICE", "0");
    buyNow = findViewById(R.id.buyNow);
    back = findViewById(R.id.back_icon);

    back.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(getApplicationContext(), MainActivity.class);
            startActivity(intent);
        }
    });

    buyNow.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
            startActivity(browserIntent);
        }
    });

    changeAudioAmplitudeScaleFactor(8);

    mPlayerManager = new PlayerManager();
    mPlayerManager.onCreate();

    LibCore.getInstance(ConnectDeviceActivity.this).setFiltering(true);
}

trying to place at the bottom of "onCreate" it gives me the following error:

PopupWindow $BadTokenException: Unable to add window — token null is not valid

1 Answers1

0

Regarding you error

PopupWindow $BadTokenException: Unable to add window — token null is not valid

Maybe add that code in the Activity onResume() lifecykle method instead of onCreate if it need to run more then one time

Move the scanningThread, BluetoothAdapter and LocalBroadcastManager LibCore everything to the 'onCreate()' . The 'onCreateView()' should only have the view = inflater.inflate(R.layout.fragment_home_2, container, false);

The onCreate() only initiate stuff hook up local variables views and set clicklisteners. Like all the one-time-stuff. Going from Fragment to Activity is basically almost the same since they have the same lifecykle methods

Check this nice explanation about the-android-lifecycle-cheat-sheet

Erik
  • 5,039
  • 10
  • 63
  • 119
  • you mean what's in "onCreateView" and "onViewCreated" should come on "onResume" and in this exact order right? – ALEXANDRE CHAGAS VIEIRA JUNIOR Sep 13 '19 at 14:04
  • Move the scanningThread, BluetoothAdapter and LocalBroadcastManager LibCore everything to the onCreate() . The onCreateView() should only have the 'view = inflater.inflate(R.layout.fragment_home_2, container, false);' – Erik Sep 13 '19 at 14:09
  • The "onCreate()" only initiate stuff hook up local variables views and set clicklisteners. Like all the one-time-stuff. Going from Fragment to Activity is basically almost the same since they have the same lifecykle methods – Erik Sep 13 '19 at 14:17