Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Friday, March 10, 2017

Moving to Kotlin

I am going to start a new job and my goal is to go Kotlin. I have been writing Android apps in Java for a number of years. Part of that time I also wrote iOS apps in ObjC. At the job I just left I only did Java Android programming.

I learned a lot at the job including ButterKnife, Dagger, Google Analytics, Flurry Analytics, Event Bus, Twillio, BrainTree, Timber, Vector Drawables, and Glide. All of those things make Java programming easier. I also used a number of things that I used at previous jobs including Volley, GSON, AndroidSVG, and  Google Play Services.

Now it is time to move forward into the land of Kotlin. I have been using it for a number of smaller command line utilities. I had used Python for things like that in the past and I found I can whip them out just as quickly in Kotlin plus it let me learn a new language that I could also use for Android.

I then stepped up and converted a small app that I had done in Java to Kotlin using the Anko library and then I wrote an animation test program from scratch from Kotlin using XML for the layout. Gave me a good peek into a number of aspects of Kotlin. I learned how to setup Kotlin for Android. My utilities were done with IntelliJ.

The old company was moving away from native development so there was not desire there to change to a new native language even if we did it bits and pieces at a time. Sure there was no harm doing some one off utilities but no way I was going to get Kotlin into the main apps.

Next up was taking some time to learn what libraries I might be able to use with Kotlin. There was an excellent talk by Jake Wharton about Okio. It started from the base of the pyramid and worked all the way up through OkHTTP, Moshi and Retrofit. Gave me a great understanding of the entire tree and what it is much better than NIO. Excited to use this chain of tools and to get away from the massive boilerplate of Volley when making REST calls. Annotations are your friend.

Don't know if I will use DSL and Anko but I might use the SQLite aspects of it. I like some of what it offers but also like seeing the preview of my layouts in XML. I do plan on using ConstraintLayout as I have used MigLayout for Java desktop and Autolayout for iOS so I think I can pick it up pretty quickly. I can pull off all kinds of things with RelativeLayout, LinearLayout, TableLayout, GridLayout and PercentLayout bit it seems silly to keep mixing all those together.

Scary to make all these changes at the same time. Kotlin will have me looking up how to do some things I already know to do easily in Java and general syntax. I have a decent base of knowledge now but I will probably fall back into old habits for speed. I know there is a lot of new syntax to use with Kotlin. Of course working code is what counts, using every trick may tighten up the code but is not a requirement. As I learn more I am sure I will go back to fairly fresh code and update it. Refactoring as you learn is a good idea.

I have watched enough Kotlin videos to know what bits and pieces are there so I will attempt to use as much as I have learned. I also think the iOS code written in Swift by the current developer will help me make the switch as it has a lot of the same programming patterns used by Kotlin.

Having a solid Android understanding is huge. I already know what I can do in Android, know about Activity and Fragment life cycles, know what the various Views do and can do recycler views with multiple row types. It will be more about learning syntax of a language and how to tie things together using Kotlin patterns.

Nervous and excited for this new life adventure. Not going to miss the old semicolon and constant null pointer checks. Will take a little bit but I bet my programming speed increases and I actually end up writing less code than I have been writing in Java.

Wednesday, October 23, 2013

Mavericks, Java, Android Studio, GIT

I installed Mavericks today on my MacBook Pro. The install went fine but it stop me cold for developing on my Android project. Sweet Apple revenge? Not really, they just don't install the developer tools you need by default. I wish the update would look at what you had and update to match but it does not. I did an update of the OS, not a clean install.

Some are getting prompted to install the Apple version of Java 6. I did not get prompted to do so the first time I tried to start up Android Studio. It just did nothing, no bouncing icon and no error message. Highly annoying and not user friendly.

Apple link to Java 6 that works on Mavericks http://support.apple.com/kb/DL1572

With that installed I was able to fire up Android Studio but it could not find GIT. I shut it down.

I was waiting on the install of Xcode to finish. Once that was done I fired up Xcode and it decided to grab the developer command line tools. Now GIT is installed and ready to go.

I appear to be back up and running as far as my Android and iOS development goes.

Outlook is acting weird. It decided to sort of dock itself and moving it just popped back into place when I tried to move it. I then tried Window -> Minimize and restore but that did not help so I did Window -> Zoom and then Outlook did some odd animation witch under a house shrinking up into the corner. I did command Q to quit and restart. It came up with half an email message scrolled off the screen. Doing View -> Navigation Pane seemed to get it back in order for now. It is painting weird in that you can only see half the "Today"header of the email headers.

Macports is not working. First it could not find GNUTAR so I did the following:

sudo ln -s /usr/bin/tar /usr/bin/gnutar

Which let it update and start the update of apps but now it has new issues. They plan and releasing an update soon so I am going to wait on that.

What I really want fixed is the crappy multiple monitor support of Mountain Lion. I really hope Mavericks makes that better. So far it has been a real time killer to get things up and running as a developer though.

I really miss Xtrafinder too. I know Apple added tabs but the other huge feature to me is the ability to sort directories to the top of the listing always. I understand if you don't like that but give us a freaking setting Apple! I don't want to scroll all over to find a stupid directory intermixed with my files. I am sure there are plans to update that too.

Thursday, September 6, 2012

Convert Numeric keypad [ENTER] to [TAB] in java

Our data entry staff does a lot of numeric entry. Java uses the [TAB] key to move between entry fields. I was asked if we could have the NumPad [ENTER] key act like the [TAB] key greatly speeding up data entry. I was able to pull it off with a little bit of code.


import java.awt.AWTEvent;
import java.awt.AWTException;
import java.awt.EventQueue;
import java.awt.Robot;
import java.awt.event.KeyEvent;

/**
 * Special event queue to convert NUMPAD + ENTER into TAB
 *
 * @author kevin.peck
 * @date Sep 4, 2012
 */
public class CustomEventQueue extends EventQueue {
    private Robot robot;
    private boolean swapKeys;

    /**
     * Constructor
     *
     * Get robot running so we can fake key events
     */
    public CustomEventQueue() {
        super();
        try {
            robot = new Robot();
        } catch (AWTException e) {
            System.out.println("Unable to get robot running " + e);
        }
    }

    /**
     * @param swapKeys  true to force key swap processing
     */
    public void setSwapKeys(boolean swapKeys) {
        this.swapKeys = swapKeys;
    }

    /**
     * @return  true if we are doing key swap processing
     */
    public boolean areKeysSwapped() {
        return swapKeys;
    }

    /**
     * Watch for keyevents and convert NUMPAD ENTER key into TAB key
     */
    @Override
    protected void dispatchEvent(AWTEvent event) {
        if (swapKeys && event instanceof KeyEvent) {
            KeyEvent keyEvent = (KeyEvent)event;
            if (keyEvent.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD && keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
                if (keyEvent.getID() == KeyEvent.KEY_PRESSED) {
                    robot.keyPress(KeyEvent.VK_TAB);
                    robot.keyRelease(KeyEvent.VK_TAB);
                }
                return;
            }
        }
        super.dispatchEvent(event);
    }
}

Add this to your main code (class derived from JFrame)
    private CustomEventQueue eventQueue = new CustomEventQueue();

Add this to the constructor or initialization routine of the class derived from JFrame
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                EventQueue ev = Toolkit.getDefaultToolkit().getSystemEventQueue();
                eventQueue.setSwapKeys(true);
                ev.push(eventQueue);
            }
        });

Why is there a setSwapKeys() method? So you can turn off this functionality. I set enabled the sample above but in my code it is actually reading a Preference setting. You can enable / disable the [ENTER] = [TAB] at any time in your code by invoking the swap keys method.

If swap keys is enabled I eat the VK_ENTER from the numeric keypad for both PRESSED and RELEASED events. I use the Robot object to send out a VK_TAB press and release on the PRESSED event. Nothing is sent on the VK_ENTER RELEASED event. 

Why am I installing the queue invokeLater? I was not doing that an it ran just fine on Java 1.7 but on Java 1.6 I would get an exception. Putting it on the EDT solved that issue.

So far it seems to be working like a champ. With minimal modifications you can watch for any event you need to perform special actions. Don't go crazy but have fun.

Tuesday, June 12, 2012

Testing your code, pretend you are an end user

What is one of the best ways to test your code? Pretend you are an end user. Run it like you bought it instead of like you are testing it.

Near the end of this release I add export to CSV for the scheduler. People want all sorts of reports so why not let them export the data and do whatever they fancy in Excel? Works like a charm. I was doing some other testing and though "Hey, I will just export the data so I can sort it and see it in Excel to fix this bug!". Whammo, I hit a bug right away in the Export dialog.

I just wanted to export the appointment ID, start time and duration so I deleted all the other fields in the list box but then I could not add any back. The list box was reporting a selected index of 4 (the original count of items in the list) even though there were no items in the list. I changed the code to ask the backing data model for the row count so I could insert at the proper place and one bug fixed.

Next I wanted to sort the exported data. The problem is recurring appointments exported with the start date of the recurrence not the data of the grid which means they sorted in front of non-recurring appointments. When I export data I want the date to be the same for all appointments and just for the time to change. I fixed that issue too in the fixes branch and trunk.

Here I am using the software like an end user and finding bugs. Most developers are afraid to test like an end user. We are scared of finding bugs. We tend to test in a little vacuum, testing small bits of code in very isolated conditions. No user runs your program like that. They dive in and hit every menu item and button trying to make it do what they want. They multi-select, drag and drop, double click, press disabled controls and have all sorts of fun. You need to do that too. Beat on your program like it owes you money.

For the days leading up the release I just ran the software and found a number of usability issues. Why can I set default cell width for open / closed business hours but not overall row height? Why is the pivot set per view and not just once for grid? Either you like Time as a row or a column and don't want that to change if you change the other axis to Category, Provider or Facility. Yes it annoyed the technical writer that I changed this late in the game but the code and writing took us an hour and this is something that would annoy the user every day. It annoyed me after playing with the program for an hour.

You can't depend on your QA staff to be an end user. A lot of the time they are running through regression testing scripts following a very narrow path through your code. They don't mind finding bugs so they will beat on things in odd ways but it is still a view with blinders on. Those test tend to skip over usability and look at functionality. Yes, you can follow these 10 steps to get from Y to Z but why are there 10 steps? Can we do it in 5? Export was two layers deep in a menu but is something that many will use everyday to print out a reminder call list. I put it as a button on the main toolbar. Once I did that I made a note to make the toolbar layout configurable so those who don't use that button don't need to see it. I plan on implementing that in the next release.

It is so easy to just keep adding features figuring that will make clients happy but remember they are still using the existing features on a daily basis and those should be easy to use with as few steps as possible. I save off the settings they used the last time the exported data. Who wants to reconfigure that everyday? Maybe you do three types of exports. I allow you save as many named export as you want. Where do you write the file? I default to the user home directory. What if you give that export definition to another person? They don't have a directory called c:\users\john.doe so I write out {home.dir} instead of c:\users\john.doe and do replacement text when you load the export definition. Don't annoy your users, computers are there to eliminate steps and avoid the mundane.

Allow multiple ways to do things. Some people are mouse / menu folks and others use hot keys. If you use hot keys use them all over otherwise heavy keyboard users will be annoyed. Some like toolbars and will use tooltips to see what they do if the icon is not obvious. Others are text oriented and want to find what they want in the menu. Menus need to be logically laid out with descriptive text. I hate a menu that has "Preferences", "Options" and "Tools" - those words mean the same thing to me and I always pick the wrong one when I want to change a setting. Microsoft I am looking at you here with nearly every Office application. Use you tech writing team or someone you consider to be a wordsmith to help here.

Take the time to nurture your application. Don't just keep throwing more stuff at it watching it bloat up. Consolidate smaller dialogs when possible. No one likes to bring up 10 dialogs to get their initial preferences in place or to have to remember where to find some obscure setting.

You want them to be able to quick find and use every feature you have. Why waste time coding it if no ones knows it is there?

Thursday, June 7, 2012

Sync one minute Java timer to the current time

I am working on a patient scheduler and I need to draw a line across the screen indicating the current time. Helps them not create appointments in the past. We also have a clock on screen via the Jide status bar. It was driving me crazy that the line moved down or across screen but not in sync with clock. That means the line might move at the 20 second mark of the clock all depending on when you started up the program. Turns out it was adding one line of code to get them within one second of being in sync which made me happy.

timer = new Timer(60000, this);
// Force initial delay to sync within a second of current clock
Calendar cal = Calendar.getInstance();
timer.setInitialDelay((60 - cal.get(Calendar.SECOND)) * 1000);
timer.setRepeats(true);
timer.start();

It is the one line of code setting the initial delay that solves the problem. After that the timer triggers every 60 seconds and away we go. Just makes things look so much cleaner.

Wednesday, April 4, 2012

Java Graphics.translate is very slow

To get around an issue I was having with a JIDE CellSpanTable in a JideScrollPane hosted by a JXLayer I was using graphics.translate(x, y) but it was killing the speed of my code. I don't know what the issue happens to be with JXLayer when you call setViewPosition a Viewport of a table. It gets out of sync with JXLayer but only in the Y axis. X seems to be fine no matter what. I need to set the view port position to open of business when the grid first starts up and then at other times as I reload data from the server.

To get around the bug I used a hack of sending the new Y offset into my renderer so I could call translate and all would paint fine. It painted just as expected but the speed was horrendous. I am using the JXLayer so I can drag an appointment around on the scheduler. I fixed the problem by adjusting just the two rectangles I use for painting instead of doing a translate on the entire graphics canvas. Paints just as fast as it did before now.

It has always been slow on the Mac with or without the translate. In fact the translate call seemed to make no difference on the Mac as far as speed goes. On my i7 with 6g of RAM running Win7 64bit the speed was unusable with the translate in place.

Since this is all happening in drag and drop code trying to put a profiler on it was going to be near impossible. I knew it was running fast before so I commented out things I had recently added until I got my speed back. I knew I had made the rendering code more flexible so I thought maybe a loop in there was causing the issues. Luckily for me I had some old test code with the old rendering code and it was running slow too so I figured it had to be the recently add translate call.

It still feels like my solution is a hack and I would love to get rid of it. I tried all sorts of SwingUtilities.invokeLater variations along with setting view port position, getting horizontal and vertical scrollbar positions, resetting view port and then setting the scrollbar positions but it still just screwed up. I don' think this is a JIDE issue. I think it would screw up with a standard JTable and JScrollPane. Somehow JXLayer is just getting out of kilter.

As far as the scheduler goes it is working nicely. I have been making things faster, easier to use and cleaning up dialog box clutter. I have probably removed more lines than I have added and the whole thing is a lot easier to understand with data in objects instead of in maps with list of other maps. There are still new features to be added and it has not been seen over in QA yet.

Friday, February 10, 2012

Java needs a toDebugString to go with toString

toString() is a very handy Java method. It allows you and the debugger to display the value of an object in a nice format. The problem is toString() is not just used by the debugger and by your code for logging. This method is used by ListBoxes, Trees, ComboBoxes and other UI elements.

It would be great to add a second method toDebugString() that returns the string to be used by the debugger when inspecting objects and potentially for your logging leaving toString() for UI elements use. In the base Object toDebugString() would return toString() so unless you override toDebugString() they would both act identically. I have various objects that I want to use in a ListBox so I have to use toString() to return a very basic String for a variable usually called name or description. That is great for a ListBox but not for the debugger where I may want to know the name, colors, child count or any number of other things.

I just got done converting some handy debug toString() methods to the much simpler return name; variety in the scheduler code as I needed to show them in the UI. I just lost useful output in the debugger from this. I can easily do my own toDebugString() calls for logging and simple inspection but the Eclipse debugger will not call that when viewing then in a watch list.

Of course Eclipse helps in this area by allowing you to create Detail Formatters. Under Window -> Preferences -> Java -> Debug -> Detail Formatters you can define what you want displayed for various object types. It means you get to go through some extra hoops but you can see the results you want. I really would like to avoid the hoops and have a call right in the code for the object as it is easier to maintain than diving deep into an Eclipse dialog to set things. During initial development I tend to refactor my objects quite a bit.This is not portable to another IDE and if you keep a lot of projects open under a workspace this can get rather cluttered.

I am going to attempt to use the Eclipse Detail Formatters while testing / debugging this project to see how it goes. It could be my fears are unjustified but I really would love a simple / clean solution to this issue easily supported by all IDE / Debuggers.

Thursday, January 19, 2012

The land of JXLayer

I am deeper into the MigCalendar to JIDE conversion process. I am still working on the prototype for the scheduler control and have a good hunk of the rendering working. That means I get to play with drag to size and drag to move. I am using a JXLayer to handle this as the main JIDE grid needs to do its own row height and column width sizing that I don't want to screw up. JXLayer is really nice in that your can paint anything on a glass pain after all the stuff under the glass has already rendered. I have appointments so I keep their rounded rectangle associated to them. If the cursor is over / near the top or bottom edge of the rounded rectangle I paint a thicker border for the rectangle in the JXLayer. The JXLayer also watches for mouse press / release actions for the thick border rectangle so I can start dragging operations allowing the user to resize the appointment to a new time frame.

Next up was the auto scrolling of the JideScrollPane as they near the edges of the screen. I have to monitor the viewport rectangle for changes while I am in my dragging code to adjust my rectangles. Lots and lots of point and rectangle processing going on in this code along with clipping and offset calculations. At this point it is all working rather nicely although I can get it to screw up a bit from time to time. I need to figure out snapping to time slots. I don't want to increment by the minute but maybe 15 minutes is too much. They can always popup a true time editor dialog to get exact numbers. The drag to size needs to be reasonable but not so crappy you will never use it. Dragging the appointment to another cell in the grid also needs to happen. For that I am thinking of a simple drag to let you move it anywhere, a CTRL + drag to only move the appointment vertically (i.e. change start time) and a SHIFT + drag to only move horizontally (i.e. under another provider, facility, room or category depending on the current column configuration). There are a lot of time you only want to change one axis and I know a lot of paint programs use CTRL, ALT and SHIFT to lock the mouse movement.

With that in mind I am considering a "status bar" custom control to show the tool tip text, row (time slot) and column (provider, etc.) information as multiple level row / column headers can be off screen meaning you don't know exactly where you are in the grid always without this special status information.

 Writing a scheduler has been a unique experience for sure. You see various 3rd party .NET controls that emulate Outlook in one fashion or another. There is almost nothing other than MigLayout on the Java side. We need to be cross platform so .NET is out even though I know how to code in C#. The other choice would be a web based product but we a lot of support data that needs to be cached leaving that out too.

Sometimes writing your own control is the only option. I have used JXLayer in the past to draw spinning busy cursors. I had not used it for mouse interaction. It has been pretty easy so far once you figure out your painting offsets based on the scrollpane and other JComponents you are dealing with. Not sure what I would do if I need to port this to a touch interface for iOS or Android. My boss got Ice Cream Sandwich on this Xoom this morning. My updates always seem to be a day or so later in the staggered refresh cycle but I am excited to give it a shot when it magically appears. He tried our mobile app out under it and it appeared to work fine. Not a big surprise as the same code base works on phones and tablets. I am using 2.1 as minimum required API so I am not using any cool fragments or other tablet features that appeared in the 3.x series. I just want to see the bad boy running and to play with the new OS stuff.