Thursday, August 22, 2013

Detecting If An Android App Is In The Background

Was trying to understand when does my app go to the background. The Activity lifecycle methods does not help, as they can be called when switching between activities inside my app.
After a bit of googling, I found this: http://www.apptentive.com/blog/detecting-android-app-starts-and-stops/

Very good, and works like a charm, but please replace the calls to commit() with calls to apply() - see my previous post here: http://srooltheknife.blogspot.com/2013/08/stackoverflow-programming.html


Tuesday, August 20, 2013

StackOverflow Programming

Programming is my profession. I am doing this for a long time (damn, its over 30 years by now).

In the early stages of my career, the way to learn the trade, was by one of three ways:
- get subscription to some early stage hobbyist magazine (I fondly remember Byte magazine)
- get some books
- get a mentor

I was lucky enough to have a great mentor that introduced me to the field - my uncle Dani who was a programmer in the 70s doing really cool stuff (real-time, complex systems that were ahead of their time). He introduced me to object-oriented programming before it was IN, using languages as Forth, and Modula. He helped me get my first Mac (the cost of which was like a used car here).

Anyway, at that time you had to read a lot. From paper.

Fast forward 15 years, and the internet was taking the stage.

Now, knowledge quickly started to spread, be shared, and be available to everyone.

Fast forward 15 more years, and now our brains are re-wired. We don't remember anything we learn. We don't have to... (see the book "The Shallows" for more on this subject - link below).

Its the age of StackOverflow programming.

Sometimes, it is great. Sometimes its a dangerous, or problematic way... Here's a little anecdote.

Doing Android programming, I stored some long term values in the SharedPreferences object. Turns out that some examples on the internet tell you to use editor.commit() after you store or modify your values.
Well, if you don't need the result of this, you would be better off if you use editor.apply().

As the Android documentation say:

Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures. If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit()will block until all async commits are completed as well as the commit itself.
As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value.
You don't need to worry about Android component lifecycles and their interaction with apply() writing to disk. The framework makes sure in-flight disk writes from apply() complete before switching states
References: http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()

Maybe the lesson here is really "Read the Documentation" and don't just code by copy and paste - at this age of Stack Overflow programming, spend the time reading. At least from time to time...


Edit: some people raised a concern that with apply() you need to worry about "race conditions" or other issues. Again, READ THE DOCS (as quoted above):

As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value.



Monday, August 5, 2013

Keerbot Drawing Program

My friend Gilad is building a wall drawing robot.

A very cool one.

You can see some of his work here: http://www.keerbot.com/

Gilad asked me to write a little utility that will allow him to better debug the robot. This little tool allows you to draw on the PC, and then save the resulting drawing to a text file with G-Codes the robot can understand. It's a C# Visual Studio 2010 express project, but you can easily adopt it to any .Net environment.

I think it's a good tutorial for anyone who wants to create a simple Windows drawing program.

Hope you like that, and go check the Keerbot site and stay tuned for more cool stuff from Gilad.

So, here is the code, and you can get the whole VisualStudio project here: https://dl.dropboxusercontent.com/u/3647610/KeerbotProject.zip

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

// Keerbot Drawing Creator Program
//
// Written by: Israel Roth
//
// This code is provided with no warranties, but its free to use for any purpose.
//
// (c) 2013. Israel Roth
//

namespace Keerbot1
{
    public partial class Form1 : Form
    {
        private bool isMouseDown = false;
        private List points;
        private List> shapes;

        // scalePoint translate a point from the screen coordinates to the Keerbot coordinate space

        private Point scalePoint(Point inPoint)
        {
            int xx = (inPoint.X - 175) * 2;
            int yy = (250 - inPoint.Y) * 2;
            return new Point(xx, yy);
        }

        public Form1()
        {
            InitializeComponent();
            points = new List(100);
            shapes = new List>(10);
        }

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            isMouseDown = true;
        }

        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            isMouseDown = false;
            if (points.Count > 2)
            {
                shapes.Add(points);
            }
            points = new List(100);
        }
                                                                                                                                                                            
        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            Point scaled = scalePoint(e.Location);
            toolStripStatusLabel1.Text = scaled.X + "," + scaled.Y;
            if (isMouseDown)
            {
                points.Add(new Point(e.X, e.Y));
                panel1.Invalidate();
            }

        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            if (shapes.Count > 0)
            {
                foreach (List s in shapes)
                {
                    DrawPoints(s, e);
                }
            }
            DrawPoints(points, e);
       }

        private void DrawPoints(List points, PaintEventArgs e)
        {
            if (points.Count > 2)
            {
                Pen pen = new Pen(Color.Black, 1);
                Point[] pArray = points.ToArray();
                e.Graphics.DrawLines(pen, pArray);
            }
         }

        private void button1_Click(object sender, EventArgs e)
        {
            saveFileDialog1.ShowDialog();
        }

        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            string name = saveFileDialog1.FileName;
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(name))
            {
                foreach (List s in shapes)
                {
                    bool isFirst = true;
                    foreach (Point q in s)
                    {
                        Point p = scalePoint(q);
                        if (isFirst)
                        {
                            file.WriteLine(startLineText.Text + " X" + p.X + " Y" + p.Y + " Z" + zUpText.Text);
                            isFirst = false;
                        }
                        else
                        {
                            file.WriteLine(startLineText.Text + " X" + p.X + " Y" + p.Y + " Z" +
                                                                                    zDownText.Text);
                        }
                    }
                }
            }

        }

        private void clearButton_Click(object sender, EventArgs e)
        {
            shapes.Clear();
            points.Clear();
            panel1.Invalidate();
        }

    }
}