pretty

Monday, 4 August 2014

Pattern with empty regexp in Java

Pattern.compile("") with empty regexp produces matches for any string, be it empty or non-empty.
    Pattern p = Pattern.compile("");
    Matcher m = p.matcher("abc");
    while (m.find()) {
        Log.i("Matcher start: ",  String.valueOf(m.start()));
        Log.i("Matcher end: ",  String.valueOf(m.end()));
    }

This listing will produce the following output:
I/Matcher start:﹕ 0
I/Matcher end:﹕ 0
I/Matcher start:﹕ 1
I/Matcher end:﹕ 1
I/Matcher start:﹕ 2
I/Matcher end:﹕ 2
I/Matcher start:﹕ 3
I/Matcher end:﹕ 3

String "abc" contains 4 empty characters. Empty character starts and ends at the same position in a text in contrast to say character "a"; "a" starts at position 0 and ends at 1. String "" will also match this pattern, with both matcher.start() and matcher.end() equal to 0.

Contrast an empty character to an empty string.
    Pattern p = Pattern.compile("^$");

This pattern with an "empty string" regexp will not match the "abc" string but will match the "" string. The "" is an empty string that also contains an empty character.

There are a lot of ways to supply regexp that wouldn't much anything, for example the "$matchnothing" regexp, as $ denotes the end of the line and no character can exist thereafter.

Friday, 25 July 2014

RxJava for UI events on Android example

In the paper Deprecating the Observer Pattern, part 3 "Reactors: composable observers without inversion of control" there is an example of the reactor that processes mouse input events, written in Scala using scala-react library. In this post I'll describe how to create composable observers for touch events for Android with RxJava library.

The tools used are the RxJava library itself and retrolambda plugin to employ lambda functions on Android. Here is the sample build.gradle file with these two dependencies. To bridge from Android event listeners to RxJava Observers the Subject is created, it will listen to touch events and reemit them to RxJava Observers.
private final PublishSubject mTouchSubject = PublishSubject.create();
 
public MouseDragView(Context context, AttributeSet attr) {
        super(context, attr);
        
        setOnTouchListener((View v, MotionEvent event) -> {
            mTouchSubject.onNext(event);
                return true;
        });
}


Then the Observables are created by filtering the Subject Observable and each of them exposes corresponding event stream to touch ups, moves and touch downs. While each of these three new observables will receive all the events from the Subject Observable, they will call their subcribers' onNext() function only for the events that suit the filter predicate.

private final Observable mTouches = mTouchSubject.asObservable();
    private final Observable mDownObservable = 
               mTouches.filter(ev -> ev.getActionMasked() == MotionEvent.ACTION_DOWN);
    private final Observable mUpObservable =
               mTouches.filter(ev -> ev.getActionMasked() == MotionEvent.ACTION_UP);
    private final Observable mMovesObservable =
               mTouches.filter(ev -> ev.getActionMasked() == MotionEvent.ACTION_MOVE);


Path should be created with the touch down event. So the new Observer is spawned using the subcribe (final Action1 onNext) function of Observable. The lambda function that is passed as an argument will be the newly created Observer's onNext() handler.

    mDownObservable.subscribe(downEvent -> {
           final Path path = new Path();
           path.moveTo(downEvent.getX(), downEvent.getY());
           Log.i(downEvent.toString(), "Touch down");
    });


After the path is created and has the starting point, lets watch for the move events.

 mDownObservable.subscribe(downEvent -> {
            final Path path = new Path();
            path.moveTo(downEvent.getX(), downEvent.getY());
            Log.i(downEvent.toString(), "Touch down");

            mMovesObservable
                    .subscribe(motionEvent -> {
                        path.lineTo(motionEvent.getX(), motionEvent.getY());
                        draw(path);
                        Log.i(motionEvent.toString(), "Touch move");
            });
        });


For each touch down event the new Observer for move events is created. Now we need to also create an Observer for touch up event. On touch up we'll unsubscribe from move events, and close the path. It's important to unsubscribe because otherwise for each next touch down we will be creating yet another moves Observer while leaving behind all the moves Observers created for previous touch downs. The unsubscription is achieved via takeUntil() operator. The RxJava wiki states that takeUntil() "emits the items from the source Observable until another Observable emits an item or issues a notification. This means that our Observer will be automatically unsubscribed from moves Observable when touch up Observable emits an item. Hence the moves Observable will become "cold" Observable, as it doesn't have Observers, and will stop emitting the items.

    mDownObservable.subscribe(downEvent -> {
            final Path path = new Path();
            path.moveTo(downEvent.getX(), downEvent.getY());
            Log.i(downEvent.toString(), "Touch down");

            mMovesObservable
                     .takeUntil(mUpObservable
                             .doOnNext(upEvent -> {
                                 draw(path);
                                 path.close();
                                 Log.i(upEvent.toString(), "Touch up");
                             }))
                    .subscribe(motionEvent -> {
                        path.lineTo(motionEvent.getX(), motionEvent.getY());
                        draw(path);
                        Log.i(motionEvent.toString(), "Touch move");
                    });

        });


The full example project for Android Studio is at github



Friday, 13 December 2013

On Android NDK and Activity Lifecycle

After activity restarts calls to native methods may fail.

This can happen because shared library does not get reloaded. There is no symmetric method to System.loadLibrary(String libName) to manually unload or reload library. The shared library on Android will be unloaded when there are no processes that use it. Even when activity finishes its lifecycle and its onDestroy() method is called the host process of activity may still run. From the Android docs "the process hosting the activity may killed by the system at any time" after activity is finished. I think it would be killed when OS will need more memory for other tasks.

So, if the old process still sticks around so does the shared library. After activity starts again, its onCreate() called etc, it attaches to the same running process and deals with the same shared library instance. The shared library's data section where all static and global variables are stored is still in the state it was carrying old values.

Now, to highlight the possible problem, suppose we have a Singleton class on a native side. We call in to a native function to create it from activity's onCreate method. The native method may look like this.

CSomeSingleton* CSomeSingleton::GetInstance()
{
    if (m_Instance == NULL)
        m_Instance = new CSomeSingleton();
    return m_Instance;
}


In activity's onDestroy we call in to another native method that destroys it. Suppose it looks like this.

void CSomeSingleton::FreeInstance()
{
    delete m_Instance;
}


After acivity restarts and attaches to same process the problem arises. m_Instance will not be NULL, it will point to invalid address in memory.

There are 3 variants to unravel this issue.

1. Do not deinitialize your native-side objects at all (in activity's onDestroy()). When new activity instance will start it would attach to running process with valid pointers and global variables. If the process would be killed by the time, it would be started again, reloading the shared library, reinitializing the data section.

2. Find all places where the global/static variables where left in inconsistent state. For the above example that would be

void CSomeSingleton::FreeInstance()
{
    delete m_Instance;
    m_Instance = NULL;
}


3. Call System.exit(0) in onDestory() to stop the process and thus unload the shared library. Considered as a bad practice, because you may have yet another component that is running in that process, and this component may be not in the appropriate state to stop its execution (because it may have some unsaved data).