How to set two selection providers in one view - eclipse-plugin

I have a view where I have two tree viewers. In the createPartControl() how I can set the selectionProviders for both the views. It takes either one of them.
Here is my snippet.
The View code:
IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IWorkbenchPartSite activePartSite = workbenchWindow.getActivePage().getActivePart().getSite();
activePartSite.setSelectionProvider(inputTreeViewer);
activePartSite.setSelectionProvider(compositeTreeViewer);
// Here the last line the selection provider code for the top one.
// Hence I only get selections from the second tree.
How can we solve the problem? I tried with inheriting the view class from ISelectionProvider and overriding getSelection() method. But that was not of any help.
Can someone suggest something?

I suggest to add a focus listener to each of the trees and call partSite.setSelectionProvider() with the currently focused tree viewer. For example:
treeViewer1.getTree().addListener( SWT.FocusIn, event -> site.setSelectionProvider( treeViewer1 ) );
treeViewer2.getTree().addListener( SWT.FocusIn, event -> site.setSelectionProvider( treeViewer2 ) );
I'll leave it as an exercise to the reader to remove the listener-duplication.
Alternatively, you can create a proxy selection provider that listens for selection changes in both tree viewers and propagates the most recent selection. Something along these lines:
public class ProxySelectionProvider implements ISelectionProvider {
private ISelection selection;
private final Collection<ISelectionChangedListener> listeners;
public ProxySelectionProvider( StructuredViewer... viewers ) {
listeners = new ArrayList<>();
selection = StructuredSelection.EMPTY;
for( StructuredViewer viewer : viewers ) {
ISelectionChangedListener selectionListener = this::selectionChanged;
viewer.addSelectionChangedListener( selectionListener );
viewer.getControl().addDisposeListener( event -> viewer.removeSelectionChangedListener( selectionListener ) );
}
}
#Override
public void addSelectionChangedListener( ISelectionChangedListener listener ) {
listeners.add( listener );
}
#Override
public void removeSelectionChangedListener( ISelectionChangedListener listener ) {
listeners.remove( listener );
}
#Override
public ISelection getSelection() {
return selection;
}
#Override
public void setSelection( ISelection selection ) {
this.selection = selection;
}
private void selectionChanged( SelectionChangedEvent event ) {
selection = event.getSelection();
notifyListeners();
}
private void notifyListeners() {
SelectionChangedEvent event = new SelectionChangedEvent( this, selection );
new ArrayList<>( listeners ).forEach( listener -> listener.selectionChanged( event ) );
}
}
Use the selection provider like this:
ISelectionProvider selectionProvider = new ProxySelectionProvider( treeViewer1, treeViewer2 );
IWorkbenchPartSite partSite = workbenchWindow.getActivePage().getActivePart().getSite();
partSite.setSelectionProvider( selectionProvider );

I solved this problem using this approach.
public class SelectionProviderAdapater implements IPostSelectionProvider {
public class InternalListener implements ISelectionChangedListener, FocusListener {
#Override
public void focusGained(FocusEvent e) {
doFocusChanged(e.widget);
}
#Override
public void focusLost(FocusEvent e) {
}
#Override
public void selectionChanged(SelectionChangedEvent event) {
doSelectionChanged(event);
}
}
/**
* The array of viewers.
*/
private StructuredViewer[] viewers;
/**
* The current viewer in focus.
*/
private StructuredViewer viewerInFocus;
/**
* The list of selection changed listeners.
*/
private final ListenerList selectionChangedListeners = new ListenerList();
/**
* The list of post selection changed listeners.
*/
private final ListenerList postSelectionChangedListeners = new ListenerList();
/**
* The internal listener instance.
*/
private final InternalListener internalListener = new InternalListener();
/**
* The internal post selection listener instance.
*/
private final ISelectionChangedListener internalPostSelectionListener = new ISelectionChangedListener() {
#Override
public void selectionChanged(SelectionChangedEvent event) {
doPostSelectionChanged(event);
}
};
#Override
public void addPostSelectionChangedListener(ISelectionChangedListener listener) {
postSelectionChangedListeners.add(listener);
}
#Override
public void addSelectionChangedListener(ISelectionChangedListener listener) {
selectionChangedListeners.add(listener);
}
/**
* Sets the viewer in focus and fires selection change events.
*
* #param control
* The {#link Widget} that has gained focus.
*/
private void doFocusChanged(Widget control) {
for (StructuredViewer viewer : viewers) {
if (viewer.getControl() == control) {
propagateFocusChanged(viewer);
return;
}
}
}
/**
* Fires post selection changed events if the {#link SelectionChangedEvent}
* 's selection provider is the current viewer in focus.
*
* #param event
* The selection changed event.
*/
private void doPostSelectionChanged(SelectionChangedEvent event) {
ISelectionProvider provider = event.getSelectionProvider();
if (provider == viewerInFocus) {
firePostSelectionChanged();
}
}
/**
* Fires selection changed events if the {#link SelectionChangedEvent}'s
* selection provider is the current viewer in focus.
*
* #param event
* The selection changed event.
*/
private void doSelectionChanged(SelectionChangedEvent event) {
ISelectionProvider provider = event.getSelectionProvider();
if (provider == viewerInFocus) {
fireSelectionChanged();
}
}
/**
* Notifies post selection changed listeners of a selection changed event.
*/
private void firePostSelectionChanged() {
if (postSelectionChangedListeners != null) {
SelectionChangedEvent event = new SelectionChangedEvent(this, getSelection());
Object[] listeners = postSelectionChangedListeners.getListeners();
for (Object listener : listeners) {
ISelectionChangedListener selectionChangedListener = (ISelectionChangedListener) listener;
selectionChangedListener.selectionChanged(event);
}
}
}
/**
* Notifies selection changed listeners of a selection changed event.
*/
private void fireSelectionChanged() {
if (selectionChangedListeners != null) {
SelectionChangedEvent event = new SelectionChangedEvent(this, getSelection());
Object[] listeners = selectionChangedListeners.getListeners();
for (Object listener : listeners) {
ISelectionChangedListener selectionChangedListener = (ISelectionChangedListener) listener;
selectionChangedListener.selectionChanged(event);
}
}
}
#Override
public ISelection getSelection() {
if (viewerInFocus != null) {
return viewerInFocus.getSelection();
}
return StructuredSelection.EMPTY;
}
public StructuredViewer getViewerInFocus() {
return viewerInFocus;
}
/**
* Sets the viewer as the viewer in focus and fires selection changed
* events.
*
* #param viewer
* The new viewer in focus.
*/
private void propagateFocusChanged(StructuredViewer viewer) {
if (viewer != viewerInFocus) {
viewerInFocus = viewer;
fireSelectionChanged();
firePostSelectionChanged();
}
}
#Override
public void removePostSelectionChangedListener(ISelectionChangedListener listener) {
postSelectionChangedListeners.remove(listener);
}
#Override
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
selectionChangedListeners.remove(listener);
}
#Override
public void setSelection(ISelection selection) {
if (viewerInFocus != null) {
viewerInFocus.setSelection(selection);
}
}
/**
* Sets the selection on the current viewer in focus.
*
* #param selection
* The selection to set.
* #param reveal
* true if the selection is to be made visible, and false
* otherwise
*/
public void setSelection(ISelection selection, boolean reveal) {
if (viewerInFocus != null) {
viewerInFocus.setSelection(selection, reveal);
}
}
/**
* Sets the collection of viewers to be monitored by this mediator.
*
* #param newViewers
* The collection of viewers.
*/
public void setViewers(Collection<? extends StructuredViewer> newViewers) {
// Remove listeners from any previous viewers.
if (viewers != null) {
for (StructuredViewer viewer : viewers) {
viewer.removeSelectionChangedListener(internalListener);
viewer.removePostSelectionChangedListener(internalPostSelectionListener);
Control control = viewer.getControl();
if (!control.isDisposed()) {
control.removeFocusListener(internalListener);
}
}
}
viewers = null;
viewerInFocus = null;
if (newViewers != null) {
viewers = newViewers.toArray(new StructuredViewer[newViewers.size()]);
for (StructuredViewer viewer : viewers) {
viewer.addSelectionChangedListener(internalListener);
viewer.addPostSelectionChangedListener(internalPostSelectionListener);
Control control = viewer.getControl();
control.addFocusListener(internalListener);
if (control.isFocusControl()) {
propagateFocusChanged(viewer);
}
}
}
}
}
Create an instance of this class in your view.Set the viewers using setViewers() method which are needed to be listened for selection.Then set it as the selection provider.It should start working.

Related

How to turn on flash in picture mode

[SOLVED]
After searching for an answer, I didn't find a solution for turning on the flash when in picture mode.
The app opens the camera in the background, and continulsy processes the pictures and detects objects, but the phone is located in a container which doesn't have light there, thus I need to make sure the flash is always opened.
There can be other approaches I'm considering as well and I'm not sure how to get these approaches to work also:
Switch to Video Mode. (Because I'm processing the pictures of the camera preview anyway, and in video mode the flash mode can work w/o recording a vide).
Set the camera default app to different app which supports image preview with flash when tapping on screen (I'll need to figure out how to switch to different app and how to simulate tapping, maybe even with another device which is connected to the app w/ bluetooth and sends clicks).
Override camera's API and make sure the Flash can be on, or just disabled and let another app turn on the flash.
This doesn't seem to work: (in the last code block)
Camera.Parameters parameters = camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
Solution 1 or 3 should be ideal, any ideas how to make it work? This is the code I'm using:
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.ImageReader;
import android.media.ImageReader.OnImageAvailableListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.tensorflow.lite.examples.classification.customview.AutoFitTextureView;
import org.tensorflow.lite.examples.classification.env.Logger;
public class CameraConnectionFragment extends Fragment {
private static final Logger LOGGER = new Logger();
/**
* The camera preview size will be chosen to be the smallest frame by pixel size capable of
* containing a DESIRED_SIZE x DESIRED_SIZE square.
*/
private static final int MINIMUM_PREVIEW_SIZE = 320;
/** Conversion from screen rotation to JPEG orientation. */
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final String FRAGMENT_DIALOG = "dialog";
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
/** A {#link Semaphore} to prevent the app from exiting before closing the camera. */
private final Semaphore cameraOpenCloseLock = new Semaphore(1);
/** A {#link OnImageAvailableListener} to receive frames as they are available. */
private final OnImageAvailableListener imageListener;
/** The input size in pixels desired by TensorFlow (width and height of a square bitmap). */
private final Size inputSize;
/** The layout identifier to inflate for this Fragment. */
private final int layout;
private final ConnectionCallback cameraConnectionCallback;
private final CameraCaptureSession.CaptureCallback captureCallback =
new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureProgressed(
final CameraCaptureSession session,
final CaptureRequest request,
final CaptureResult partialResult) {}
#Override
public void onCaptureCompleted(
final CameraCaptureSession session,
final CaptureRequest request,
final TotalCaptureResult result) {}
};
/** ID of the current {#link CameraDevice}. */
private String cameraId;
/** An {#link AutoFitTextureView} for camera preview. */
private AutoFitTextureView textureView;
/** A {#link CameraCaptureSession } for camera preview. */
private CameraCaptureSession captureSession;
/** A reference to the opened {#link CameraDevice}. */
private CameraDevice cameraDevice;
/** The rotation in degrees of the camera sensor from the display. */
private Integer sensorOrientation;
/** The {#link Size} of camera preview. */
private Size previewSize;
/** An additional thread for running tasks that shouldn't block the UI. */
private HandlerThread backgroundThread;
/** A {#link Handler} for running tasks in the background. */
private Handler backgroundHandler;
/**
* {#link TextureView.SurfaceTextureListener} handles several lifecycle events on a {#link
* TextureView}.
*/
private final TextureView.SurfaceTextureListener surfaceTextureListener =
new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(
final SurfaceTexture texture, final int width, final int height) {
openCamera(width, height);
}
#Override
public void onSurfaceTextureSizeChanged(
final SurfaceTexture texture, final int width, final int height) {
configureTransform(width, height);
}
#Override
public boolean onSurfaceTextureDestroyed(final SurfaceTexture texture) {
return true;
}
#Override
public void onSurfaceTextureUpdated(final SurfaceTexture texture) {}
};
/** An {#link ImageReader} that handles preview frame capture. */
private ImageReader previewReader;
/** {#link CaptureRequest.Builder} for the camera preview */
private CaptureRequest.Builder previewRequestBuilder;
/** {#link CaptureRequest} generated by {#link #previewRequestBuilder} */
private CaptureRequest previewRequest;
/** {#link CameraDevice.StateCallback} is called when {#link CameraDevice} changes its state. */
private final CameraDevice.StateCallback stateCallback =
new CameraDevice.StateCallback() {
#Override
public void onOpened(final CameraDevice cd) {
// This method is called when the camera is opened. We start camera preview here.
cameraOpenCloseLock.release();
cameraDevice = cd;
createCameraPreviewSession();
}
#Override
public void onDisconnected(final CameraDevice cd) {
cameraOpenCloseLock.release();
cd.close();
cameraDevice = null;
}
#Override
public void onError(final CameraDevice cd, final int error) {
cameraOpenCloseLock.release();
cd.close();
cameraDevice = null;
final Activity activity = getActivity();
if (null != activity) {
activity.finish();
}
}
};
#SuppressLint("ValidFragment")
private CameraConnectionFragment(
final ConnectionCallback connectionCallback,
final OnImageAvailableListener imageListener,
final int layout,
final Size inputSize) {
this.cameraConnectionCallback = connectionCallback;
this.imageListener = imageListener;
this.layout = layout;
this.inputSize = inputSize;
}
/**
* Given {#code choices} of {#code Size}s supported by a camera, chooses the smallest one whose
* width and height are at least as large as the minimum of both, or an exact match if possible.
*
* #param choices The list of sizes that the camera supports for the intended output class
* #param width The minimum desired width
* #param height The minimum desired height
* #return The optimal {#code Size}, or an arbitrary one if none were big enough
*/
protected static Size chooseOptimalSize(final Size[] choices, final int width, final int height) {
final int minSize = Math.max(Math.min(width, height), MINIMUM_PREVIEW_SIZE);
final Size desiredSize = new Size(width, height);
// Collect the supported resolutions that are at least as big as the preview Surface
boolean exactSizeFound = false;
final List<Size> bigEnough = new ArrayList<Size>();
final List<Size> tooSmall = new ArrayList<Size>();
for (final Size option : choices) {
if (option.equals(desiredSize)) {
// Set the size but don't return yet so that remaining sizes will still be logged.
exactSizeFound = true;
}
if (option.getHeight() >= minSize && option.getWidth() >= minSize) {
bigEnough.add(option);
} else {
tooSmall.add(option);
}
}
LOGGER.i("Desired size: " + desiredSize + ", min size: " + minSize + "x" + minSize);
LOGGER.i("Valid preview sizes: [" + TextUtils.join(", ", bigEnough) + "]");
LOGGER.i("Rejected preview sizes: [" + TextUtils.join(", ", tooSmall) + "]");
if (exactSizeFound) {
LOGGER.i("Exact size match found.");
return desiredSize;
}
// Pick the smallest of those, assuming we found any
if (bigEnough.size() > 0) {
final Size chosenSize = Collections.min(bigEnough, new CompareSizesByArea());
LOGGER.i("Chosen size: " + chosenSize.getWidth() + "x" + chosenSize.getHeight());
return chosenSize;
} else {
LOGGER.e("Couldn't find any suitable preview size");
return choices[0];
}
}
public static CameraConnectionFragment newInstance(
final ConnectionCallback callback,
final OnImageAvailableListener imageListener,
final int layout,
final Size inputSize) {
return new CameraConnectionFragment(callback, imageListener, layout, inputSize);
}
/**
* Shows a {#link Toast} on the UI thread.
*
* #param text The message to show
*/
private void showToast(final String text) {
final Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(
new Runnable() {
#Override
public void run() {
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
}
});
}
}
#Override
public View onCreateView(
final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(layout, container, false);
}
#Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
textureView = (AutoFitTextureView) view.findViewById(R.id.texture);
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
startBackgroundThread();
// When the screen is turned off and turned back on, the SurfaceTexture is already
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if (textureView.isAvailable()) {
openCamera(textureView.getWidth(), textureView.getHeight());
} else {
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
}
#Override
public void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
public void setCamera(String cameraId) {
this.cameraId = cameraId;
}
/** Sets up member variables related to camera. */
private void setUpCameraOutputs() {
final Activity activity = getActivity();
final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
final StreamConfigurationMap map =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
// Danger, W.R.! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
previewSize =
chooseOptimalSize(
map.getOutputSizes(SurfaceTexture.class),
inputSize.getWidth(),
inputSize.getHeight());
// We fit the aspect ratio of TextureView to the size of preview we picked.
final int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
textureView.setAspectRatio(previewSize.getWidth(), previewSize.getHeight());
textureView.setVisibility(View.GONE);
} else {
textureView.setAspectRatio(previewSize.getHeight(), previewSize.getWidth());
textureView.setVisibility(View.GONE);
}
} catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
} catch (final NullPointerException e) {
// Currently an NPE is thrown when the Camera2API is used but not supported on the
// device this code runs.
// TODO(andrewharp): abstract ErrorDialog/RuntimeException handling out into new method and
// reuse throughout app.
ErrorDialog.newInstance(getString(R.string.camera_error))
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
throw new RuntimeException(getString(R.string.camera_error));
}
cameraConnectionCallback.onPreviewSizeChosen(previewSize, sensorOrientation);
}
/** Opens the camera specified by {#link CameraConnectionFragment#cameraId}. */
private void openCamera(final int width, final int height) {
setUpCameraOutputs();
configureTransform(width, height);
final Activity activity = getActivity();
final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
manager.openCamera(cameraId, stateCallback, backgroundHandler);
} catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
} catch (final InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
/** Closes the current {#link CameraDevice}. */
private void closeCamera() {
try {
cameraOpenCloseLock.acquire();
if (null != captureSession) {
captureSession.close();
captureSession = null;
}
if (null != cameraDevice) {
cameraDevice.close();
cameraDevice = null;
}
if (null != previewReader) {
previewReader.close();
previewReader = null;
}
} catch (final InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
cameraOpenCloseLock.release();
}
}
/** Starts a background thread and its {#link Handler}. */
private void startBackgroundThread() {
backgroundThread = new HandlerThread("ImageListener");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
}
/** Stops the background thread and its {#link Handler}. */
private void stopBackgroundThread() {
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
backgroundHandler = null;
} catch (final InterruptedException e) {
LOGGER.e(e, "Exception!");
}
}
/** Creates a new {#link CameraCaptureSession} for camera preview. */
private void createCameraPreviewSession() {
try {
final SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
// This is the output Surface we need to start preview.
final Surface surface = new Surface(texture);
// We set up a CaptureRequest.Builder with the output Surface.
previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
previewRequestBuilder.addTarget(surface);
LOGGER.i("Opening camera preview: " + previewSize.getWidth() + "x" + previewSize.getHeight());
// Create the reader for the preview frames.
previewReader =
ImageReader.newInstance(
previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2);
previewReader.setOnImageAvailableListener(imageListener, backgroundHandler);
previewRequestBuilder.addTarget(previewReader.getSurface());
// Here, we create a CameraCaptureSession for camera preview.
cameraDevice.createCaptureSession(
Arrays.asList(surface, previewReader.getSurface()),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(final CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == cameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
captureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
previewRequestBuilder.set(
CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// Flash is automatically enabled when necessary.
// previewRequestBuilder.set(
// CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
previewRequestBuilder.set(
CaptureRequest.FLASH_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
// Finally, we start displaying the camera preview.
previewRequest = previewRequestBuilder.build();
captureSession.setRepeatingRequest(
previewRequest, captureCallback, backgroundHandler);
} catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
}
}
#Override
public void onConfigureFailed(final CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
},
null);
} catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
}
}
}
}
The second one:
public class LegacyCameraConnectionFragment extends Fragment {
private static final Logger LOGGER = new Logger();
/** Conversion from screen rotation to JPEG orientation. */
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private Camera camera;
private Camera.PreviewCallback imageListener;
private Size desiredSize;
/** The layout identifier to inflate for this Fragment. */
private int layout;
/** An {#link AutoFitTextureView} for camera preview. */
private AutoFitTextureView textureView;
/**
* {#link TextureView.SurfaceTextureListener} handles several lifecycle events on a {#link
* TextureView}.
*/
private final TextureView.SurfaceTextureListener surfaceTextureListener =
new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(
final SurfaceTexture texture, final int width, final int height) {
int index = getCameraId();
camera = Camera.open(index);
try {
Camera.Parameters parameters = camera.getParameters();
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes != null
&& focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
List<Camera.Size> cameraSizes = parameters.getSupportedPreviewSizes();
Size[] sizes = new Size[cameraSizes.size()];
int i = 0;
for (Camera.Size size : cameraSizes) {
sizes[i++] = new Size(size.width, size.height);
}
Size previewSize =
CameraConnectionFragment.chooseOptimalSize(
sizes, desiredSize.getWidth(), desiredSize.getHeight());
parameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());
camera.setDisplayOrientation(90);
camera.setParameters(parameters);
camera.setPreviewTexture(texture);
} catch (IOException exception) {
camera.release();
}
camera.setPreviewCallbackWithBuffer(imageListener);
Camera.Size s = camera.getParameters().getPreviewSize();
camera.addCallbackBuffer(new byte[ImageUtils.getYUVByteSize(s.height, s.width)]);
textureView.setAspectRatio(s.height, s.width);
camera.startPreview();
}
#Override
public void onSurfaceTextureSizeChanged(
final SurfaceTexture texture, final int width, final int height) {}
#Override
public boolean onSurfaceTextureDestroyed(final SurfaceTexture texture) {
return true;
}
#Override
public void onSurfaceTextureUpdated(final SurfaceTexture texture) {}
};
/** An additional thread for running tasks that shouldn't block the UI. */
private HandlerThread backgroundThread;
#SuppressLint("ValidFragment")
public LegacyCameraConnectionFragment(
final Camera.PreviewCallback imageListener, final int layout, final Size desiredSize) {
this.imageListener = imageListener;
this.layout = layout;
this.desiredSize = desiredSize;
}
#Override
public View onCreateView(
final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(layout, container, false);
}
#Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
textureView = (AutoFitTextureView) view.findViewById(R.id.texture);
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
startBackgroundThread();
// When the screen is turned off and turned back on, the SurfaceTexture is already
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if (textureView.isAvailable()) {
camera.startPreview();
} else {
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
}
#Override
public void onPause() {
stopCamera();
stopBackgroundThread();
super.onPause();
}
/** Starts a background thread and its {#link Handler}. */
private void startBackgroundThread() {
backgroundThread = new HandlerThread("CameraBackground");
backgroundThread.start();
}
/** Stops the background thread and its {#link Handler}. */
private void stopBackgroundThread() {
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
} catch (final InterruptedException e) {
LOGGER.e(e, "Exception!");
}
}
protected void stopCamera() {
if (camera != null) {
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
}
private int getCameraId() {
CameraInfo ci = new CameraInfo();
for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, ci);
if (ci.facing == CameraInfo.CAMERA_FACING_BACK) return i;
}
return -1; // No camera found
}
}
SOLUTION: in second block code:
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON);
mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
and in first block code:
//Check Whether device supports AutoFlash, If you YES then set AutoFlash
List<String> flashModes = parameters.getSupportedFlashModes();
if (flashModes.contains(android.hardware.Camera.Parameters.FLASH_MODE_AUTO))
{
parameters.setFlashMode(parameters.FLASH_MODE_AUTO);
}
SOLUTION: in second block code:
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON);
mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
and in first block code:
//Check Whether device supports AutoFlash, If you YES then set AutoFlash
List<String> flashModes = parameters.getSupportedFlashModes();
if (flashModes.contains(android.hardware.Camera.Parameters.FLASH_MODE_AUTO))
{
parameters.setFlashMode(parameters.FLASH_MODE_AUTO);
}

get selected checkboxs from tableview

I have tableview with checkbox in each row and I have an action button. My problem is that, how can I get selected checkbox from tableview to apply an action when the button is pressed?
This is how I add the checkbox to the tableview
public void addCeckBoxToTableView() {
/** define a simple boolean cell value for the action column so that the column will only be shown for non-empty rows. */
tcCb.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Object, Boolean>,
ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Object, Boolean> p) {
return new SimpleBooleanProperty(p.getValue() != null);
}
});
/** create a cell value factory with an add button for each row in the table. */
tcCb.setCellFactory(new Callback<TableColumn<Object, Boolean>, TableCell<Object, Boolean>>() {
#Override
public TableCell<Object, Boolean> call(TableColumn<Object, Boolean> p) {
return new CheckBoxCell();
}
});
}
private class CheckBoxCell extends TableCell<Object, Boolean> {
CheckBox checkBox = new CheckBox();
HBox hb = new HBox(checkBox);
/**
* places button in the row only if the row is not empty.
*/
#Override
protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(hb);
} else {
setGraphic(null);
}
}
}
cordially.
I'm of the same opinion as James: "with that setup you can't"
But you could do it this way
private TableView<Record> table;
private TableColumn<Record, Boolean> tcCb;
private Button actionButton;
public class Record {
private SimpleBooleanProperty selected = new SimpleBooleanProperty();
public SimpleBooleanProperty selectedProperty() {
return selected;
}
}
#Override
public void start(Stage primaryStage) throws Exception {
table = new TableView<Record>(FXCollections.observableArrayList(new Record(), new Record(), new Record()));
table.setEditable(true);
// Create "CheckBox" - Column
tcCb = new TableColumn<Record, Boolean>("Boolean-Column");
tcCb.setCellValueFactory(new PropertyValueFactory<Record, Boolean>("selected"));
tcCb.setCellFactory(CheckBoxTableCell.forTableColumn(tcCb));
tcCb.setEditable(true);
table.getColumns().add(tcCb);
// Create actionButton for retrieving cellData
actionButton = new Button("action");
actionButton.setOnAction(actionEvent -> {
for (int row = 0; row < table.getItems().size(); row++) {
System.out.println(tcCb.getCellData(row));
}
});
// The uninteresting stuff...
primaryStage.setScene(new Scene(new VBox(table, actionButton)));
primaryStage.show();
}
The UI elements should associate them with the object. In your example, you wanted to apply the action on items which are selected(Selected CheckBox).
The Object associated with the table can be like this
public class TableData{
private Boolean selected=Boolean.False;
public void setSelected(Boolean isSelected){
this.isSelected = isSelected;
}
public boolean isSelected(){
return this.selected;
}
}
So In TableCell,
When the checkBox is selected, update 'selected' Boolean value of TableData,by adding a selection action listener to the CheckBox.
then you can iterate through the TableData which you can get it from the TableView, to apply the actions upon Button selection.

Recycler View: Inconsistency detected. Invalid view holder adapter positionViewHolder

Recycler View Inconsistency Detected error, coming while scrolling fast or scrolling while loading more items..
FATAL EXCEPTION: main
Process: com.pratap.endlessrecyclerview, PID: 21997
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{56a082c position=40 id=-1, oldPos=39, pLpos:39 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4251)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4382)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4363)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:562)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2864)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1445)
at android.support.v7.widget.RecyclerView.access$400(RecyclerView.java:144)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:282)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Adapter
public class DataAdapter extends RecyclerView.Adapter {
private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;
private List<Feed> mFeed;
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
private boolean loading;
private OnLoadMoreListener onLoadMoreListener;
public DataAdapter(List<Feed> feeds, RecyclerView recyclerView) {
mFeed = feeds;
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView
.getLayoutManager();
recyclerView
.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView,
int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager
.findLastVisibleItemPosition();
if (!loading
&& totalItemCount <= (lastVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
loading = true;
}
}
});
}
}
#Override
public int getItemViewType(int position) {
return mFeed.get(position) == null ? VIEW_PROG : VIEW_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
RecyclerView.ViewHolder vh;
if (viewType == VIEW_ITEM) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.list_row, parent, false);
vh = new StudentViewHolder(v);
}
else {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.progress_item, parent, false);
vh = new ProgressViewHolder(v);
}
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof StudentViewHolder) {
Feed singleStudent= (Feed) mFeed.get(position);
((StudentViewHolder) holder).tvName.setText(singleStudent.getTitle());
((StudentViewHolder) holder).student= singleStudent;
} else {
ProgressViewHolder.PROGRESS_BAR.setIndeterminate(true);
}
}
public void setLoaded() {
loading = false;
}
public void addFeed(Feed feed) {
mFeed.add(feed);
//mFeed.addAll(0, (Collection<? extends Feed>) feed);
notifyItemInserted(mFeed.size());
//notifyItemRangeInserted(0,mFeed.size());
notifyDataSetChanged();
//notifyItemInserted(mFeed.size());
//setLoaded();
//notifyItemInserted(mFeed.size());
}
public void removeAll(){
mFeed.clear();
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return mFeed.size();
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
public static class StudentViewHolder extends RecyclerView.ViewHolder {
public TextView tvName;
public Feed student;
public StudentViewHolder(View v) {
super(v);
tvName = (TextView) v.findViewById(R.id.tvName);
//tvEmailId = (TextView) v.findViewById(R.id.tvEmailId);
}
}
public static class ProgressViewHolder extends RecyclerView.ViewHolder {
//public ProgressBar progressBar;
public static ProgressBar PROGRESS_BAR;
public ProgressViewHolder(View v) {
super(v);
PROGRESS_BAR = (ProgressBar) v.findViewById(R.id.progressBar1);
// progressBar = (ProgressBar) v.findViewById(R.id.progressBar1);
}
}
}
Activity
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
private Toolbar toolbar;
private TextView tvEmptyView;
private RecyclerView mRecyclerView;
private DataAdapter mAdapter;
private LinearLayoutManager mLayoutManager;
private RestManager mManager;
private List<Feed> mFeed;
SwipeRefreshLayout mSwipeRefreshLayout;
protected Handler handler;
private int currentPage=1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
tvEmptyView = (TextView) findViewById(R.id.empty_view);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mSwipeRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
mSwipeRefreshLayout.setOnRefreshListener(this);
//studentList = new ArrayList<Student>();
mFeed = new ArrayList<Feed>();
handler = new Handler();
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("Android Students");
}
mManager = new RestManager();
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
// use a linear layout manager
mRecyclerView.setLayoutManager(mLayoutManager);
// create an Object for Adapter
mAdapter = new DataAdapter(mFeed,mRecyclerView);
// set the adapter object to the Recyclerview
mRecyclerView.setAdapter(mAdapter);
// mAdapter.notifyDataSetChanged();
loadData(false);
// if (mFeed.isEmpty()) {
// mRecyclerView.setVisibility(View.GONE);
// tvEmptyView.setVisibility(View.VISIBLE);
//
// } else {
// mRecyclerView.setVisibility(View.VISIBLE);
// tvEmptyView.setVisibility(View.GONE);
// }
mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
//add null , so the adapter will check view_type and show progress bar at bottom
mFeed.add(null);
mAdapter.notifyItemInserted(mFeed.size() - 1);
handler.postDelayed(new Runnable() {
#Override
public void run() {
// remove progress item
mFeed.remove(mFeed.size() - 1);
// mAdapter.notifyItemRemoved(mFeed.size());
//add items one by one
int start = mFeed.size();
currentPage++;
Log.d("CurrentPage", String.valueOf(currentPage));
Call<Results> listCall = mManager.getFeedApi().getAllFeeds(1);
listCall.enqueue(new Callback<Results>() {
#Override
public void onResponse(Call<Results> call, Response<Results> response) {
mSwipeRefreshLayout.setRefreshing(false);
if (response.isSuccess()) {
if (response.body() != null) {
Results feedList = response.body();
// List<Results> newUsers = response.body();
Log.d("Retrofut", String.valueOf(feedList));
for (int i = 0; i < feedList.results.size(); i++) {
Feed feed = feedList.results.get(i);
// mFeed.add(feed);
mAdapter.addFeed(feed);
// mAdapter.notifyDataSetChanged();
//mAdapter.notifyItemInserted(mFeed.size());
}
// mAdapter.notifyDataSetChanged();
}
}
}
#Override
public void onFailure(Call<Results> call, Throwable t) {
Log.d("Retrofut", "Error");
mFeed.remove(mFeed.size() - 1);
mAdapter.notifyItemRemoved(mFeed.size());
mAdapter.setLoaded();
mSwipeRefreshLayout.setRefreshing(false);
}
});
// for (int i = 1; i <= 20; i++) {
// studentList.add(new Student("Student " + i, "androidstudent" + i + "#gmail.com"));
//
// }
mAdapter.setLoaded();
//or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
}
}, 2000);
}
});
}
// load initial data
private void loadData(final boolean removePreData) {
Call<Results> listCall = mManager.getFeedApi().getAllFeeds(1);
listCall.enqueue(new Callback<Results>() {
#Override
public void onResponse(Call<Results> call, Response<Results> response) {
if (response.isSuccess()) {
if (response.body() != null) {
// if(removePreData) mAdapter.removeAll();
Results feedList = response.body();
Log.d("Retrofut", String.valueOf(feedList));
for (int i = 0; i < feedList.results.size(); i++) {
Feed feed = feedList.results.get(i);
// mFeed.add(feed);
//mAdapter.notifyDataSetChanged();
mAdapter.addFeed(feed);
}
mSwipeRefreshLayout.setRefreshing(false);
}
}
}
#Override
public void onFailure(Call<Results> call, Throwable t) {
Log.d("Retrofut", String.valueOf(t));
mFeed.remove(mFeed.size() - 1);
mAdapter.notifyItemRemoved(mFeed.size());
mAdapter.setLoaded();
mSwipeRefreshLayout.setRefreshing(false);
}
}
);
// for (int i = 1; i <= 20; i++) {
// studentList.add(new Student("Student " + i, "androidstudent" + i + "#gmail.com"));
//
// }
mSwipeRefreshLayout.setRefreshing(true);
}
#Override
public void onRefresh() {
mFeed.clear();
mAdapter.notifyDataSetChanged();
loadData(true);
currentPage=1;
}
}
put this line along with setting recyclerView. issue was fixed by
setting ItemAnimator to null for RecyclerView.
in kotlin
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.itemAnimator = null
in java
recyclerView.setItemAnimator(null);
It looks similar with known android bug
There are quite ugly, but working approach
public class WrapContentLinearLayoutManager extends LinearLayoutManager {
//... constructor
#Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
Log.e("Error", "IndexOutOfBoundsException in RecyclerView happens");
}
}
}
mRecyclerView.setLayoutManager(new WrapContentGridLayoutManager(getContext(), spanCount));
For me it works without any by-effect.
This issue is a known bug of RecyclerView. The best solution is, clear the list every time before refresh RecyclerView.
For fix this issue just call notifyDataSetChanged() with empty list before updating recycle view.
For example
//Method for refresh recycle view
if (!yourList.isEmpty())
yourList.clear(); //The list for update recycle view
adapter.notifyDataSetChanged();
Use this to refresh a RecyclerView
items.clear(); //here items is an ArrayList populating the RecyclerView
adapter.notifyDataSetChanged();
items.addAll(list);// add new data
adapter.notifyItemRangeInserted(0, items.size);// notify adapter of new data
`
I had similiar issue, and also this solution has helped me, after I've added new item to my RV:
recyclerView.getRecycledViewPool().clear();
adapter.notifyDataSetChanged();
Maybe you can try this before refresh the adapter:
dataList.clear();
patrolListAdapter.notifyDataSetChanged();
In my case I was doing it as notifyItemInserted(position);
That caused me this issue then i used as and it worked perfectly.notifyItemRangeInserted(startIndex,endIndex);
I had this problem when scrolling fast through my endless/paging RecyclerView. The root of my problem came from the fact that I had a “header” item at the beginning of the list, this header item was not a part of the data source, it was just inserted at the beginning of the adapter list. So when scrolling fast and adding new pages of items to the RecyclerView Adapter and notify the adapter that new data had been inserted, I was not taking into account the additional header item, thus making the size of the adapter’s list wrong... and causing this exception...
So in short, if you’re using a header/footer in our RecyclerView adapter make sure you take it into account when updating the adapters data.
Example:
public void addNewPageToList(List<MyData> list)
{ //
// Make sure you account for any header/footer in your list!
//
// Add one to the currentSize to account for the header item.
//
int currentSize = this.adapterList.size() + 1;
this.adapterList.addAll(list);
notifyItemRangeInserted(currentSize, this.adapterList.size());
}
Edit:
I guess you could always just use the adapter method getItemCount() to get the size, instead of getting the size from the “data list” and adding to it. Your getItemCount() method should already be taking into account any additional headers/footers/etc that you have in your list.
The problem is in this line of code:
mFeed = feeds;
you are assigning mFeed to the caller's instance feeds so whenever the caller changes it's variable (may be adding, clearing or removing items), your local mFeed will change
try to change to
mFeed.addAll(feeds);
don't forget to initialize mFeed to any list tat fits your needs like mFeed = new ArrayList<>();
put this line along with setting recyclerView. issue was fixed by setting ItemAnimator to null for RecyclerView.
in kotlin
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.itemAnimator = null
I'm using the recyclerview from mikepenz. And any update to the items using .set(item) was causing this issue.
For some reason, setting recylerView.itemAnimator = null, resolved the issue. This is a known android bug.
In my case, I was using RecyclerView from Firebase UI. Initially, the logic to initialize the RecyclerView was in onCreate(). To fix, I put the logic in onResume() and seems to be working for me. I had this error when going back to the Activity which had the RecyclerView. So, everytime the Activity screen is refreshed, the new data is loaded.
I had similar problem. Removing all views from RecyclerView helped me:
RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();
layoutManager.removeAllViews();
For me the issue was I wasn't posting notifyDatasetChanged when the data set changed as I implemented incremental search.
I had a list that was filtered based on what the user searched in the search widget. For each item in the list, I was making a remote request, and when I got the result back, I was updating that particular cell.
I had to do both notifies for the recycler view to work
Filter the original data set then post the dataset change
this.searchResultTable?.post {
this.searchResultTable?.adapter?.notifyDataSetChanged()
}
After receiving response, post notifications again
this.searchResultTable?.post {
this.searchResultTable?.adapter?.notifyItemChanged(index, updateDataHashMap)
}
You have to post updates rather than sending notifiy messages directly in order to prevent the recycler view from crashing when the update comes in before the view is laid out.
Another important gotcha is that when you post the individual updates after the remote response, you have to make sure that the list the user currently sees is the list that existed when the requests were sent.
For my case in adapter there was notifyItemRangeInserted and I replaced it with notifyItemRangeChanged

How can I detect when the XAML Slider is Completed?

In XAML I have the <Slider />. It has the ValueChanged event. This event fires with every change to Value. I need to detect when the value change is over. LostFocus, PointerReleased are not the correct event. How can I detect this?
XAML, WinRT, Windows8.1 and UWP:
PointerCaptureLost event should work for mouse / touch
KeyUp event for keyboard
You can create a new class and inherit from Slider. From there on, you can look for the Thumb control & listen for the events you want.
Something like this should work:
public class SliderValueChangeCompletedEventArgs : RoutedEventArgs
{
private readonly double _value;
public double Value { get { return _value; } }
public SliderValueChangeCompletedEventArgs(double value)
{
_value = value;
}
}
public delegate void SlideValueChangeCompletedEventHandler(object sender, SliderValueChangeCompletedEventArgs args);
public class ExtendedSlider : Slider
{
public event SlideValueChangeCompletedEventHandler ValueChangeCompleted;
private bool _dragging = false;
protected void OnValueChangeCompleted(double value)
{
if (ValueChangeCompleted != null)
{
ValueChangeCompleted(this, new SliderValueChangeCompletedEventArgs(value) );
}
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var thumb = base.GetTemplateChild("HorizontalThumb") as Thumb;
if (thumb != null)
{
thumb.DragStarted += ThumbOnDragStarted;
thumb.DragCompleted += ThumbOnDragCompleted;
}
thumb = base.GetTemplateChild("VerticalThumb") as Thumb;
if (thumb != null)
{
thumb.DragStarted += ThumbOnDragStarted;
thumb.DragCompleted += ThumbOnDragCompleted;
}
}
private void ThumbOnDragCompleted(object sender, DragCompletedEventArgs e)
{
_dragging = false;
OnValueChangeCompleted(this.Value);
}
private void ThumbOnDragStarted(object sender, DragStartedEventArgs e)
{
_dragging = true;
}
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
if (!_dragging)
{
OnValueChangeCompleted(newValue);
}
}
}
You can use pair of bool values isValueChanged and (if possible change value without manipulation of pointer
) isPressed;
private void Slider_ValueChanged(object s, RangeBaseValueChangedEventArgs e) {
if (!isPressed) {
AcceptChanges();
} else {
isValueChanged = true;
}
}
Initialization code:
Window.Current.CoreWindow.PointerPressed += (e, a) => { isPressed = true; };
Window.Current.CoreWindow.PointerReleased += (e, a) => {
isPressed = false;
if (isValueChanged) AcceptChanges();
};
I had a similar issue using a Slider on Windows8/WinRT.
My problem was the following: I was reacting to the ValueChanged Event and performing a long lasting operation (writing asynchronously to a file) after each trigger. And thus running into a concurrent editing exception. In order to avoid this, I used a DispatcherTimer.
//Class member
private DispatcherTimer myDispatcherTimer = null;
private void OnSliderValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
//I update my UI right away
...
//If the dispatcher is already created, stop it
if (myDispatcherTimer!= null)
myDispatcherTimer.Stop();
//Overwrite the DispatcherTimer and thus reset the countdown
myDispatcherTimer= new DispatcherTimer();
myDispatcherTimer.Tick += (sender, o) => DoSomethingAsync();
myDispatcherTimer.Interval = new TimeSpan(0,0,2);
myDispatcherTimer.Start();
}
private async void DoSomethingAsync()
{
await DoThatLongSaveOperation();
}
You cannot directly detect what the final value is, but you can at least delay the operation until there is a long pause between two updates (e.g. in my case, if the user drags the slider and stops while maintaining the drag for 2 seconds, the save operation will be fired anyway).

How to enable/disable a TextCellEditor

I am making an application which contains 2 views. The first one contains a tree viewer which displays the folders from my system and the second one contains a table viewer which displays the content of a directory selected in the first view. Long story short: a file explorer.
//initialization of the table viewer
tableViewer = new TableViewer(parent, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL);
tableViewer.setContentProvider(new FileTableContentProvider());
tableViewer.setLabelProvider(new FileTableLabelProvider());
//from within the implementation of any view or editor
/*
* getSite() - Returns the site for this workbench part (a workbench part can be a view (IViewPart) or an editor (IEditorPart))
* this view is a selection provider; the view sends the event to all the views registered to the selection service
*/
getSite().setSelectionProvider(tableViewer);
//the table column "Name" is added to the table viewer
TableColumn columnName = new TableColumn(tableViewer.getTable(), SWT.LEFT);
columnName.setText("Name");
columnName.setResizable(true);
columnName.setWidth(200);
//the table column "Date modified" is added to the table viewer
TableColumn columnDateModified = new TableColumn(tableViewer.getTable(), SWT.LEFT);
columnDateModified.setText("Date modified");
columnDateModified.setResizable(true);
columnDateModified.setWidth(200);
//the table column "Type" is added to the table viewer
TableColumn columnType = new TableColumn(tableViewer.getTable(), SWT.LEFT);
columnType.setText("Type");
columnType.setResizable(true);
columnType.setWidth(200);
//make the header of the table visible
tableViewer.getTable().setHeaderVisible(true);
/*
* getSite().getPage() - gets the active workbench page.
*/
getSite().getPage().addSelectionListener("com.awebofcode.fileexplorer.view.filetree",(ISelectionListener)this);
/*
* add a doubleClickListener for:
* 1) if the object selected is a file, then the file will be opened with the associated program
* 2) if the object selected is a directory, then enter the folder and update the tree viewer
*/
tableViewer.addDoubleClickListener(new IDoubleClickListener(){
#Override
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
File itemSelected = (File) selection.getFirstElement();
//if the selected item is a file a double click will launch the associated program
if (itemSelected.isFile() && itemSelected.exists()){
Program.launch(itemSelected.getAbsolutePath());
}else if (itemSelected.isDirectory()){
/*
* Update the tree viewer;
* PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(FileTreeView.ID) --> returns the view with the specified ID
* setSelection() will send an event and the setSelectionChanged will run
*/
((FileTreeView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(FileTreeView.ID)).getTreeViewer().setSelection(selection);
}
}
});
//create the cell editor
CellEditor[] editors = new CellEditor[1];
editors[0] = new TextCellEditor(tableViewer.getTable());
tableViewer.setColumnProperties(new String[]{"Name", "Date modified", "Type"});
//assign the cell editors to the table viewer
tableViewer.setCellEditors(editors);
//set the cell modifier to the table viewer
tableViewer.setCellModifier(new NameCellModifier(tableViewer));
I created an action that will rename the selected file or folder from the second view.
When I click on the name of the file I don't want to enter in the editing mode.I want to stay in the selection mode and only after I click File -> Rename (action rename) the editing mode has to be enabled.
The problem is that I cannot find how to enable/disable the TextCellEditor.
I didn't find a clean solution. I will explain you what I have done so far. I have modified the code that I have posted. I use TableViewerColumn instead of TableColumn.
Class FileTableView:
public class FileTableView extends ViewPart implements ISelectionListener{
private TableViewer tableViewer;
private boolean cellEditable = false;
private FirstColumnEditingSupport obj;
public FileTableView() {
super();
}
#Override
public void createPartControl(Composite parent) {
//initialization of the table viewer
tableViewer = new TableViewer(parent, SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.MULTI); //SWT.MULTI - for multiple selection; SWT.FULL_SELECTION - for selection of an entire row
tableViewer.setContentProvider(new FileTableContentProvider());
//it is not necessary to add a label provider for the table viewer because we will set a label provider for every column of the table
//tableViewer.setLabelProvider(new FileTableLabelProvider());
//extract the table widget of the table viewer
final Table table = tableViewer.getTable();
//make the header of the table visible
table.setHeaderVisible(true);
//hide the lines of the table
table.setLinesVisible(false);
//create the columns of the table
createColumns(parent, tableViewer);
//set the sorter to the table viewer
tableComparator = new TableViewerComparator();
tableViewer.setComparator(tableComparator);
//from within the implementation of any view or editor
/*
* getSite() - Returns the site for this workbench part (a workbench part can be a view (IViewPart) or an editor (IEditorPart))
* this view is a selection provider; the view sends the event to all the views registered to the selection service
*/
getSite().setSelectionProvider(tableViewer);
tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
public void selectionChanged(SelectionChangedEvent event){
setCellEditable(false);
}
});
}
/*
* method used to update the viewer from outside
*/
public void refresh(){
tableViewer.refresh();
}
#Override
public void setFocus() {
tableViewer.getControl().setFocus();
}
//method that returns the table viewer
public TableViewer getTableViewer(){
return tableViewer;
}
/*
* get the value of the cellEditable
*/
public boolean getCellEditable(){
return cellEditable;
}
/*
* set the value of the cellEditable
*/
public void setCellEditable(boolean cellEditable){
this.cellEditable = cellEditable;
}
public FirstColumnEditingSupport getEditingSupport(){
return obj;
}
/*
* method that creates columns of the table
*/
private void createColumns(final Composite parent, final TableViewer viewer){
String[] titles = {"Name", "Date Modified", "Size"};
int[] width = {200, 200, 200};
//first column is for the name of the file
TableViewerColumn col = createTableViewerColumn(titles[0], width[0], 0);
col.setLabelProvider(new ColumnLabelProvider(){
public String getText(Object element){
return ((File) element).getName();
}
public Image getImage(Object element){
return getFirsColumnImage((File) element);
}
});
obj = new FirstColumnEditingSupport(tableViewer,this);
col.setEditingSupport(obj);
//second column is for the last date modified
col = createTableViewerColumn(titles[1], width[1], 1);
col.setLabelProvider(new ColumnLabelProvider(){
public String getText(Object element){
return formatLastModifiedDate((File) element);
}
});
//third column is for size
col = createTableViewerColumn(titles[2], width[2], 2);
col.setLabelProvider(new ColumnLabelProvider(){
public String getText(Object element){
return formatLength((File) element);
}
});
}
private TableViewerColumn createTableViewerColumn(String title, int width, final int columnNumber){
final TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
final TableColumn column = viewerColumn.getColumn();
column.setText(title);
column.setWidth(width);
column.setResizable(true);
column.setMoveable(false);
column.addSelectionListener(getSelectionAdapter(column, columnNumber));
return viewerColumn;
}
private SelectionAdapter getSelectionAdapter(final TableColumn column, final int index){
SelectionAdapter selectionAdapter = new SelectionAdapter(){
public void widgetSelected(SelectionEvent e){
tableComparator.setColumn(index);
int direction = tableComparator.getDirection();
tableViewer.getTable().setSortDirection(direction);
tableViewer.getTable().setSortColumn(column);
tableViewer.refresh();
}
};
return selectionAdapter;
}
/*
* method used to return the last modified date in "dd-MM-yyyy hh:mm:ss" format
*/
private String formatLastModifiedDate(File file){
Date d = new Date(file.lastModified());
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
return sdf.format(d);
}
/*
* method used to return the length of the file in KB
*/
private String formatLength(File file){
long size = file.length()/1024;
NumberFormat f = new DecimalFormat("#,###,### KB");
return f.format(size);
}
}
FirstColumnEditingSupport.java file:
/*
* The EditingSupport implementation defines how the content can be changed.
*/
public class FirstColumnEditingSupport extends EditingSupport {
private TableViewer tableViewer;
private FileTableView view;
private TextCellEditor textEditor;
public FirstColumnEditingSupport(TableViewer viewer, FileTableView view) {
super(viewer);
this.tableViewer = viewer;
this.view = view;
textEditor = new TextCellEditor(tableViewer.getTable());
}
#Override
/*
* (non-Javadoc)
* #see org.eclipse.jface.viewers.EditingSupport#getCellEditor(java.lang.Object)
* EditingSupport returns in his getCellEditor() method an object of type CellEditor. This object creates the controls to change the data.
*/
protected CellEditor getCellEditor(Object element) {
return textEditor;
}
#Override
/*
* (non-Javadoc)
* #see org.eclipse.jface.viewers.EditingSupport#canEdit(java.lang.Object)
* The canEdit() method defines, if the cell can be edited.
*/
protected boolean canEdit(Object element) {
return view.getCellEditable();
}
#Override
/*
* (non-Javadoc)
* #see org.eclipse.jface.viewers.EditingSupport#getValue(java.lang.Object)
* The getValue() method receives the current object and returns the value which should be displayed.
*/
protected Object getValue(Object element) {
return ((File) element).getName();
}
#Override
/*
* (non-Javadoc)
* #see org.eclipse.jface.viewers.EditingSupport#setValue(java.lang.Object, java.lang.Object)
* The method setValue() in EditingSupport receives the changed value based on the user input. In this method you assign the value to your data object.
*/
protected void setValue(Object element, Object value) {
//value is the user input
File oldFile = (File) element;
//String path = oldFile.getAbsolutePath().substring(oldFile.getAbsolutePath().lastIndexOf(File.pathSeparatorChar));
//System.out.println(oldFile.getParent());
oldFile.renameTo(new File(oldFile.getParent() + "\\" + (String) value));
tableViewer.refresh();
}
public TextCellEditor getTextCellEditor(){
return textEditor;
}
}
My RenameAction file:
public class RenameAction extends Action implements ISelectionListener, ActionFactory.IWorkbenchAction {
private final IWorkbenchWindow window;
private IStructuredSelection itemSelected;
public final static String ID = PlatformUI.PLUGIN_ID + ".RenameAction";
public RenameAction(IWorkbenchWindow window){
this.window = window;
setId(ID);
setText("&Rename");
setToolTipText("Rename the file or directory selected");
window.getSelectionService().addSelectionListener(this);
}
#Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if(selection.isEmpty() || !(selection instanceof IStructuredSelection)){
return;
}else {
itemSelected = (IStructuredSelection)selection;
}
}
public void dispose(){
window.getSelectionService().removeSelectionListener(this);
}
public void run(){
Object firstElement = itemSelected.getFirstElement();
File item = (File) firstElement;
if(item != null){
FileTableView myTreeView= (FileTableView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(FileTableView.ID);
myTreeView.setCellEditable(true);
}
}
}
My idea was:
by default: the cell editor of the first column is disabled
when the rename action is triggered (press the menu button), the cell editor of the column is enabled (myTreeView.setCellEditable(true))
the table line selected is in editing mode and you can change the name of the file. This part is not working quite well, because after you press the rename menu button, you can't see that the editing mode is enabled. After you click on the table line, the editing mode is activated. Also, the editing mode is enabled for all the table lines and I wanted to be enabled only for the selected one. For this problem I haven't got a solution.
after you finish typing the new name of the file, and change the selection (click on a different table line), the editing mode is disabled:
tableViewer.addSelectionChangedListener(new ISelectionChangedListener(){
public void selectionChanged(SelectionChangedEvent event){
setCellEditable(false);
}
});
I hope my solution can help you.