Skip to content
This repository has been archived by the owner on Mar 18, 2024. It is now read-only.

Commit

Permalink
Merge pull request #28 from R3PI/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
tomjhall authored Oct 20, 2016
2 parents 109e184 + 661c877 commit b33e0c9
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 7 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Change Log
==========

Version 1.0.0
----------------------------
* Added safe operations helper class.
* Fixed issue where ConcurrentModificationException would occur when removing listeners while traversing the listener list.

Version 0.9.0
----------------------------
* Removed deprecated code.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Defrag is available in the jCenter repository:

```java
dependencies {
compile 'com.solera.defrag:defrag:0.9.0'
compile 'com.solera.defrag:defrag:1.0.0'
}
```

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.3'
classpath 'com.android.tools.build:gradle:2.2.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
Expand Down
2 changes: 1 addition & 1 deletion defrag/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'android-apt'

group = 'com.solera.defrag'
version = '0.9.0'
version = '1.0.0'


android {
Expand Down
5 changes: 4 additions & 1 deletion defrag/src/main/java/com/solera/defrag/ViewStack.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import auto.parcel.AutoParcel;

Expand All @@ -55,7 +56,7 @@ public class ViewStack extends FrameLayout {
public static final Bundle USE_EXISTING_SAVED_STATE = new Bundle();
private static final int DEFAULT_ANIMATION_DURATION_IN_MS = 300;
private static final String SINGLE_PARAMETER_KEY = "view_stack_single_param";
private final Collection<ViewStackListener> viewStackListeners = new ArrayList<>();
private final Collection<ViewStackListener> viewStackListeners = new CopyOnWriteArrayList<>();
private final Deque<ViewStackEntry> viewStack = new ArrayDeque<>();
private TraversingState traversingState = TraversingState.IDLE;
private Object result;
Expand Down Expand Up @@ -129,10 +130,12 @@ public void onMeasured(View view, int width, int height) {
}

public void addTraversingListener(@NonNull ViewStackListener listener) {
ViewUtils.verifyMainThread();
viewStackListeners.add(listener);
}

public void removeTraversingListener(@NonNull ViewStackListener listener) {
ViewUtils.verifyMainThread();
viewStackListeners.remove(listener);
}

Expand Down
144 changes: 144 additions & 0 deletions defrag/src/main/java/com/solera/defrag/ViewStackUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.solera.defrag;

import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import java.util.List;

/**
* A collection of utilities for ViewStacks.
*/
public class ViewStackUtils {
private ViewStackUtils() {
}

/**
* Safely replace the current view as soon as the {@link ViewStack} will be in {@link
* TraversingState#IDLE}. If it is already in the idle state, method is invoked immediately.
*/
public static void safeReplace(@NonNull final ViewStack viewStack, @LayoutRes int layout) {
safeReplaceWithParameters(viewStack, layout, null);
}

/**
* Safely replace the current view as soon as the {@link ViewStack} will be in {@link
* TraversingState#IDLE}. If it is already in the idle state, method is invoked immediately.
*/
public static void safeReplaceWithParameters(@NonNull final ViewStack viewStack,
@LayoutRes final int layout, @Nullable final Bundle parameters) {
waitForTraversingState(viewStack, TraversingState.IDLE, new ViewStackListener() {
@Override
public void onTraversing(@NonNull TraversingState traversingState) {
viewStack.replaceWithParameters(layout, parameters);
}
});
}

/**
* Safely replace the {@link ViewStack} stack as soon as the {@link ViewStack} will be in {@link
* TraversingState#IDLE}. If it is already in the idle state, method is invoked immediately.
*/
public static void safeReplaceStack(@NonNull final ViewStack viewStack,
@NonNull final List<Pair<Integer, Bundle>> views) {
waitForTraversingState(viewStack, TraversingState.IDLE, new ViewStackListener() {
@Override
public void onTraversing(@NonNull TraversingState traversingState) {
viewStack.replaceStack(views);
}
});
}

/**
* Safely push a view (as soon as the {@link ViewStack} will be in {@link TraversingState#IDLE},
* if it is already in the idle state, method is invoked immediately).
*/
public static void safePush(@NonNull final ViewStack viewStack, @LayoutRes int layout) {
safePushWithParameters(viewStack, layout, null);
}

/**
* Safely push a view as soon as the {@link ViewStack} will be in {@link TraversingState#IDLE}.
* If it is already in the idle state, method is invoked immediately.
*/
public static void safePushWithParameters(@NonNull final ViewStack viewStack,
@LayoutRes final int layout, @Nullable final Bundle parameters) {
waitForTraversingState(viewStack, TraversingState.IDLE, new ViewStackListener() {
@Override
public void onTraversing(@NonNull TraversingState traversingState) {
viewStack.pushWithParameters(layout, parameters);
}
});
}

/**
* Safely pop the current view as soon as the {@link ViewStack} will be in {@link
* TraversingState#IDLE}. If it is already in the idle state, method is invoked immediately.
* <p>
* Note: You cannot be sure if the pop operation has been successful.
*/
public static void safePop(@NonNull final ViewStack viewStack) {
safePopWithResult(viewStack, null);
}

/**
* Safely pop the current view as soon as the {@link ViewStack} will be in {@link
* TraversingState#IDLE}. If it is already in the idle state, method is invoked immediately.
* <p>
* Note: You cannot be sure if the pop operation has been successful.
*/
public static void safePopWithResult(@NonNull final ViewStack viewStack,
@Nullable final Object result) {
waitForTraversingState(viewStack, TraversingState.IDLE, new ViewStackListener() {
@Override
public void onTraversing(@NonNull TraversingState traversingState) {
viewStack.popWithResult(result);
}
});
}

/**
* Safely pop to the given view layout as soon as the {@link ViewStack} will be in {@link
* TraversingState#IDLE}. If it is already in the idle state, method is invoked immediately.
* <p>
* Note: You cannot be sure if the pop operation has been successful.
*/
public static void safePopBackToWithResult(@NonNull final ViewStack viewStack,
@LayoutRes final int layout, @Nullable final Object result) {
waitForTraversingState(viewStack, TraversingState.IDLE, new ViewStackListener() {
@Override
public void onTraversing(@NonNull TraversingState traversingState) {
viewStack.popBackToWithResult(layout, result);
}
});
}

/**
* Call the given callback when viewStack will be in the given state (if it is already in the
* given state, the callback is immediately invoked).
*
* @param viewStack the viewStack to wait on
* @param desiredState the traversing state to wait on
* @param callback the callback to invoke
*/
@MainThread
private static void waitForTraversingState(@NonNull final ViewStack viewStack,
@NonNull final TraversingState desiredState, @NonNull final ViewStackListener callback) {
ViewUtils.verifyMainThread();
if (desiredState == viewStack.getTraversingState()) {
callback.onTraversing(desiredState);
} else {
viewStack.addTraversingListener(new ViewStackListener() {
@Override
public void onTraversing(@NonNull TraversingState traversingState) {
if (traversingState == desiredState) {
viewStack.removeTraversingListener(this);
callback.onTraversing(desiredState);
}
}
});
}
}
}
13 changes: 13 additions & 0 deletions defrag/src/main/java/com/solera/defrag/ViewUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package com.solera.defrag;

import android.os.Looper;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.view.View;
Expand All @@ -30,6 +31,18 @@ public class ViewUtils {
private ViewUtils() {
}

/**
* Verify that the calling thread is the Android main thread.
*
* @throws IllegalStateException when called from any other thread.
*/
public static void verifyMainThread() {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException(
"Expected to be called on the main thread but was " + Thread.currentThread().getName());
}
}

/**
* Call the given callback when the view has been measured (if it has already been measured, the
* callback is immediately invoked.
Expand Down
3 changes: 0 additions & 3 deletions defrag/src/main/res/values/strings.xml

This file was deleted.

0 comments on commit b33e0c9

Please sign in to comment.