Project JStock Development Blog

Keep track the development progress of JStock - Free Stock Market Software and JStock Android

Wednesday, April 09, 2014

Technical sharing on recent launched home widget feature


With recent launched of JStock Android, I manage to deliver home widget feature (finally). It took much longer time than I initial estimation. 8 weeks! (I work on it part-time)

Developing home widget is harder than I thought. There're 2 reasons for that.

No direct access to UI components

Developer doesn't have direct access to UI components of home widget. All UI manipulation, like setting text, is done through service. Service is only able to help developer to "set" UI's attributes. When developer wants to "get" UI's attributes, he can't! The only way is
  • When setting an attribute of an UI, like setting text for a TextView, save the attribute value in persistence storage. For instance, SharedPreferences, SQLite, ...
  • To get an attribute of an UI, read from previous stored value in SharedPreferences, SQLite, ...

No easy way to store current state of home widget

To fetch the latest stock price, and show it in ListView, here's what my first attempt looks like :-

1st Wrong Attempt - Doesn't use user thread and store data in static variables

public class JStockAppWidgetProvider extends AppWidgetProvider {
  public static final Map<Integer, Stock> stocksMap = new java.util.concurrent.ConcurrentHashMap<Integer, Stock>();

  @Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    for (int appWidgetId : appWidgetIds) {
      List<Stock> stocks = getStocks(appWidgetId);      
      stocksMap.put(appWidgetId, stocks);
      appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, android.R.id.list);
    }
  }
}

// For ListView updating
public class AppWidgetRemoteViewsService extends RemoteViewsService {
  @Override
  public void onDataSetChanged() {
    this.stocks = JStockAppWidgetProvider.stocksMap.get(appWidgetId);
  }
}

There're 2 problem with such approach.
  • getStocks is a time consuming operation. It should be done in user thread.
  • Android OS might destroy AppWidgetProvider anytime. Hence, RemoteViewsService might get a null value.
2nd Attempt - Still not optimized

public class JStockAppWidgetProvider extends AppWidgetProvider {
  private static ExecutorService executor = Executors.newFixedThreadPool(1);

  @Override
  public void onUpdate(Context context, final AppWidgetManager appWidgetManager, 
    final int[] appWidgetIds) 
  {
    Runnable runnable = new Runnable() {
      @Override
      public void run() {
        for (int appWidgetId : appWidgetIds) {
          List<Stock> stocks = getStocks(appWidgetId);      
          storeStocksInSQLite(appWidgetId, stocks);
          appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, android.R.id.list);
      }
    };
    executor.execute(runnable);
  }
}

// For ListView updating
public class AppWidgetRemoteViewsService extends RemoteViewsService {
  @Override
  public void onDataSetChanged() {
    this.stocks = readStocksFromSQLite(appWidgetId);
  }
}

This solution is not optimized yet. As, having to perform DB read access for every onDataSetChanged doesn't sound good to me. (Consume more battery, slower, ...) I modify the above code slightly, to reduce number of DB read access.

3rd Attempt - Optimized solution

public class JStockAppWidgetProvider extends AppWidgetProvider {
  public static final Map<Integer, Stock> stocksMap = new java.util.concurrent.ConcurrentHashMap<Integer, Stock>();
  private static ExecutorService executor = Executors.newFixedThreadPool(1);

  @Override
  public void onUpdate(Context context, final AppWidgetManager appWidgetManager, 
    final int[] appWidgetIds) 
  {
    Runnable runnable = new Runnable() {
      @Override
      public void run() {
        for (int appWidgetId : appWidgetIds) {
          List<Stock> stocks = getStocks(appWidgetId);      
          storeStocksInSQLite(appWidgetId, stocks);
          stocksMap.put(appWidgetId, stocks);
          appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, android.R.id.list);
      }
    };
    executor.execute(runnable);
  }
}

// For ListView updating
public class AppWidgetRemoteViewsService extends RemoteViewsService {
  @Override
  public void onDataSetChanged() {
    this.stocks = JStockAppWidgetProvider.stocksMap.get(appWidgetId);
    // Is JStockAppWidgetProvider destroyed?
    if (this.stocks == null) {
      this.stocks = readStocksFromSQLite(appWidgetId);
    }
  }
}

This is what I had learnt during home widget development process. If you find out any mistake in my finding, feel free to let me know through

Thank you very much :)

Tuesday, April 08, 2014

Looking for freelance mobile app desginer

Halo all,

Currently, I'm looking for a freelance mobile app designer, to help me achieve pixel perfection on our current stock market Android app - https://play.google.com/store/apps/details?id=org.yccheok.jstock.gui

Area of improvement I'm looking for are :-


1. Page which used to view all transactions summary. http://i.imgur.com/fJMdAZ6.png

2. Page which used to view individual transactions details. http://i.imgur.com/dz8fpil.png

3. Page which used to view all dividends summary. http://i.imgur.com/Kc3ATLJ.png


5. Any design which makes the app looks prettier & elegant.

If you have any great idea on what improvement can be done, I wish to talk to you.

Feel free to drop me an email at, along with your portfolio. (Dribble, Behance, ...)

Thank you very much!

Sunday, March 16, 2014

Home widget in progress

Home widget feature is still in progress...


Thursday, March 13, 2014

User adjustable scanning speed (Revised)

We revised our scan speed UI. The adjustable range is from 1 minute to 30 minute.


Tuesday, March 11, 2014

User adjustable scanning speed

We get a lot of similar demands recently. Hence, we decide to include this new feature in next coming release.


Sunday, March 09, 2014

Widget development progress...

Here's what we had done so far for home widget feature

A configuration page, for you to decide the watclist & theme for home widget (Completed)



 Widget after adding to home screen (Incomplete yet)


Followers