Notes

You want to do something new with IoT, RFID ?. Drop me a message :).

Sunday, January 1, 2012

Some Take Notes in Programming for Windows CE/Mobile

Le Trung Thang, New Year 2012 

.NET compact framework in Windows CE / Mobile OS comes in with support for mobile devices which have limitation of resource: RAM size, CPU speed. So, there’re some tricks may be helpful in developing the applications for this operation system.


1. Implement Set collection

Although Set is a data structure very useful in data processing but .NET compact 3.5 came in with absence of this class. So, if you need a data type like as Set then you must implement a Set class by yourself. Example below is an implementation of Set (MySet class). However, this is not a full implement version. So, you cannot use the foreach loop with this class. Instead, you should use the classic type of for loop: for( int i = 0 ; ; ).

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace ThangLe.example.common
{
public class MySet : ICollection
{
private Dictionary MyDict;

public MySet()
{
MyDict = new Dictionary();

}

// Methods
public void Add(T item)
{
// We don't care for the value in dictionary, Keys matter.
if (!MyDict.ContainsKey(item))
{
MyDict.Add(item, 0);
}
}

public void Clear()
{
MyDict.Clear();
}

public bool Contains(T item)
{
return MyDict.ContainsKey(item);
}

public void CopyTo(T[] array, int arrayIndex)
{
throw new NotImplementedException();
}

public bool Remove(T item)
{
return MyDict.Remove(item);
}

public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}

// Properties
public int Count
{
get { return MyDict.Keys.Count(); }
}

public bool IsReadOnly
{
get { return false; }
}

//====get all elements of MySet
public List getAllElement()
{

List allElement = new List();
Dictionary.KeyCollection keyColl = MyDict.Keys;

foreach (T element in keyColl)
{
allElement.Add(element);
}
return allElement;
}
// implement ElementAt
public T ElementAt(int index)
{
return MyDict.Keys.ElementAt(index);
}
}
}

2. Restriction of using global variant at least possible

Due to limitation of memory, you should restrict in declaration global variants as much possible.

3. Using Delegate for update or refresh form

If your program have using thread, then to update or refresh a form you should use delegate to do this. For example, you can update a Label in form as following:

public void setTextLabel(String text)
        {
            setTextLabel1(text, label1); // better
            //label1.Text = text; // not good
        }
        delegate void setTextLabelCallback(string value, Label label);
        private void setTextLabel1(string value, Label label)
        {
            if (label.InvokeRequired)
            {
setTextLabelCallback d = new setTextLabelCallback(setTextLabel1);
                this.BeginInvoke(d, new object[] { value, label });
            }
            else
            {
                label.Text = value;
                label.Invalidate();
            }
    }

BeginInvoke or Invoke ? In general, if your application is running on multithreading environment, then you should use BeginInvoke instead of Invoke. Invoke executes on the UI thread, but calling thread waits for completion before continuing whereas BeginInvoke executes on the UI thread, and calling thread doesn't wait for completion. So, use BeginInvoke to guarantee your threads will be not blocked due to unpredictable reasons.
Be noted: there are two kinds of invokes: Delegate.Invoke and Control.Invoke. One we mention is Control.BeginInvoke and Control.Invoke.

4. Deadlock thread in Multithreading

Unlike as the desktop Windows OS (XP, Seven), the Windows Mobile/CE is a preemptive multitasking OS, so the priority of thread is important and impact to your program. So, if your program has more than one thread then you need ensure there are not any threads will be blocked forever. A thread will be blocked forever when it has lowest priority and have no chance to be scheduled due to all the others thread don’t move to block status.
In general, you should create all threads with same a priority. Else, you should use the Thread.Sleep method in the threads which have higher priority to give other threads chance to go on running status, or any synchronize techniques to enable the lower priority threads get chance to running

5. Using Timer for Auto-close message

To create an auto-closing message for warning purpose. You shouldn’t use MessageBox.Show(msg) or Dialog. The better solution is to create a new form and give it a Timer to auto-close it after a predictable time.

private void Form1_Load(object sender, EventArgs e)
        {
            Timer autoCloseTimer = new Timer();
            // The MessageBox closes after 2 seconds
            autoCloseTimer.Interval = 2000;
            autoCloseTimer.Enabled = true;
autoCloseTimer.Tick += new EventHandler(autoCloseTimer_Tick);
        }

        public void autoCloseTimer_Tick(object sender, EventArgs e)
        {
            closeMessageForm(this);
        }
        delegate void CloseCallback(Form form);
        private void closeMessageForm(Form form)
        {
            if (form.InvokeRequired)
            {
                CloseCallback d = new CloseCallback(closeMessageForm);
                this.BeginInvoke(d, new object[] { form });
            }
            else
            {
                form.Close();
            }
   }
Auto Close message

6. Handle “Out Of Memory” exception

Because of limitation on memory size, when you need to process the big data, the program may fall down when the size of data goes over allocation capability of program. In this case, an “OutOfMemoryException” will occur at runtime. To prevent the program goes to fall down you should handle this exception at place your big data is being processed.

try
  {
 //process data here
  }
catch (OutOfMemoryException ex)
{
return; //process exception here
}

7. Management transactions with external devices

A problem you can encounter when development on Windows Mobile is that you need work with external devices like as: Printer, Sensors, Actuator… Regardless of protocols these devices support, a common thing you must do first when want communicate with them is you need to open a connection to device.
And troubles will come in with when you close the connection which you opened previously.
In normal, after opening of connection, we will communicate with device to transfer data. There are two methods to exchange data between host (your program) and client (the external device): synchronous and asynchronous. With synchronous type, the host is simply to poll to device and thus everything is usually OK, no problem. However, when you choose asynchronous type for communication then you need add event handlers of device to event listener which was created in your program. After complete accessing to device you stop communication to device by closing the connection and then the pain will come up: your program was hung-up. This is by you didn’t remove event handlers from your listener before closing connection. To overcome this, you need remove all event handlers in your listener before closing connection. Example following is a typical situation for the CN3 Intermec mobile computer (www.intermec.com) when it opens a connection to external device (Mobile RFID reader) via the Bluetooth protocol:

//Intermec computer runs on Windows Mobile 6 (www.intermec.com).
//open a connection to external device
BRIReader m_briReader = new BRIReader(IP_address);
//add event for battery infromation.
this.m_briReader.EventHandlerBattery += new 
Battery_EventHandler(bri_EventHandlerBattery); 

//exchange data with device

//remove event for battery infromation.
this.m_briReader.EventHandlerBattery -= new Battery_EventHandler(bri_EventHandlerBattery);   
//close the connection     
this.m_briReader.Dispose();
Intermec Mobile Reader

8. Work with Webservices

.NET compact 3.5 supports webservices very good, however if you call a webservices at client side, generated code is quite a lot of intricate. For example, we get a class named Person from server. If Person class at server is declared as follow:

public class Person{
private int Id;
private String name = ””;
}

Then at client site, the program may generate class Person as follow:
public class Person{
private int Id;
private bool IdSpecified ;
private String name = ””;
}

As you see at above, there is a new field was generated, that is IdSpecified, this new field is to quest you about the way you want to treat the Id field of Person class: set IdSpecified to true to indicate that field Id of Person class is an essential field, must be have. Set IdSpecified to false to indicate that field Id of Person class is a trivial field and webservices will not care to it when generate SOAP message to send to server. If you use some webservices frameworks in Java as Axis, CXF… you will not meet this problem.

Example:
Person thangLe = new Person();
thangLe.Id = 1;
thangLe.IdSpecified = true;
thangLe.name = “Thang Le”;

9. Singleton classes

In general, when working with classes at driver layer where you need perform some tasks with the device, to prevent confliction due to communication, you should instance these classes as the singleton classes.

//example for the classical singleton for a driver class
public static MobileReader getInstance()
       {
        if (intermecReader == null)
         {
         intermecReader = new IntermecReader(); //this is driver class
         }
         return intermecReader;
  }

4 comments:

mathhoang said...

Just about some ways to optimize code.

How's about storing data ?

Lê Trung Thắng said...

Compact DB or CSV file is good selections, my favourite is CSV, hehe.

mathhoang said...

anh Thắng để cái "chân rung" làm avatar như vậy, ko sợ cô nào chôm hả !!!! ka ka ka ka

Lê Trung Thắng said...

haha, đang cần người chôm đây em :))