Tutorials
Getting started
Chart interface
Web components
Chart internals
Data integration
Customization
Frameworks and bundlers
Mobile development
Plug-ins
Troubleshooting
Glossary
Reference
JSFiddles

Getting Started on Android

In this tutorial you will learn how to integrate the ChartIQ Android SDK into native Android apps. You will build the sample native app included in the SDK and instantiate and interact with a ChartIQ chart.


Overview

The ChartIQ Android SDK provides a native interface for Android developers to instantiate and interact with a ChartIQ chart. The interface creates a WebView and populates it with a predefined HTML file that loads the ChartIQ JavaScript library, supporting CSS, and a JavaScript “bridge” file which interfaces with the native application.

What occurs in the WebView is hidden, automatic, and not dependent on developer configuration. You should be able to instantiate the object as you would any other native component and essentially feel like you are working with a native component.

Important

Although the mobile SDK for Android and the JavaScript library may use the same function call names at times, they are not the same, and they are not interchangeable.

  • When using the mobile SDK, follow the documentation in the mobile native API.
  • When directly calling the JavaScript API, follow the documentation in the JavaScript CIQ core library.

Requirements

See the ChartIQ Android SDK README.

Download the ChartIQ mobile SDK

Check out the latest version of the ChartIQ Android SDK from GitHub. If you want a previous version, check out the appropriate tag.

Now, let's create a ChartIQ view in the sample app.

Create a ChartIQ view (optional)

The ChartIQ Android SDK contains a fully functional sample app. The only thing you need to provide the WebView with is an HTML file to load. Whether that is from a web server or files bundled with your Android application is up to you. The library is set by default to use the Pull mode. So unless you want to change how data is populated in the chart, have other reasons to create your own ViewModel, or want to set up specific defaults or chart loading workflow, you can skip this step and go straight to Deploy the ChartIQ mobile SDK.

  1. Import the ChartIQ library into the app's ViewModel (MainViewModel.kt).

    import com.chartiq.sdk.ChartIQ
    
  2. Now, in the MainViewModel, add code to let the chart know how to load your data (see the loadChartData function below). In this example we are using the Pull data mechanism. For a Push example, refer to the Data Integration Overview section below.

    class MainViewModel(
        private val networkManager: NetworkManager,
        private val applicationPrefs: ApplicationPrefs,
        private val chartIQ: ChartIQ,
        private val connectivityManager: ConnectivityManager) : ViewModel() {
    
    	...
    
        init {
            chartIQ.apply {
                setDataSource(object : DataSource {
                    override fun pullInitialData(
                            params: QuoteFeedParams,
                            callback: DataSourceCallback,
                    ) {
                        loadChartData(params, callback)
                    }
    
                    override fun pullUpdateData(
                            params: QuoteFeedParams,
                            callback: DataSourceCallback,
                    ) {
                        loadChartData(params, callback)
                    }
    
                    override fun pullPaginationData(
                            params: QuoteFeedParams,
                            callback: DataSourceCallback,
                    ) {
                        loadChartData(params, callback)
                    }
                })
    
                start {
                	chartIQ.setDataMethod(DataMethod.PULL, "")
            	}
    
    			...
    
            }
    	}
    
    	...
    
       // Sample code for loading data from your feed.
       // The networkManager will call the data url you have provided
       private fun loadChartData(params: QuoteFeedParams, callback: DataSourceCallback) {
        viewModelScope.launch(Dispatchers.IO) {
            val applicationId = applicationPrefs.getApplicationId()
            when (val result = networkManager.fetchDataFeed(params, applicationId)) {
                is NetworkResult.Success -> {
                    withContext(Dispatchers.Main) { callback.execute(result.data) }
                }
                is NetworkResult.Failure -> {
                    when (result.exception) {
                        is NetworkException -> withContext(Dispatchers.Main) {
                            checkInternetAvailability()
                        }
                        else -> errorLiveData.postValue(Unit)
                    }
                }
    
            }
        }
    
  3. You now need to make sure your quotefeed URL is properly configured in the network/ChartIQNetworkManager.kt file. In this example you might want to change the HOST_SIMULATOR and what parameters you pass to your URL. For example, our ChartIQ quote simulator needs the following: symbol, start and end dates, period (how many data points to roll into one bar on the chart), interval (type of data), a flag to indicate extended hours, and a unique session id. If you have to adjust your own quotefeed you will have to change the network/api/ChartAPI.kt file accordingly.

    Note: The following example uses the ChartIQ quote simulator. You should replace the code in the ViewController with your own implementation.

    	class ChartIQNetworkManager : NetworkManager {
    
    		companion object {
    	        private const val HOST_SIMULATOR = "https://mobile-simulator.chartiq.com"
    	        private const val DEFAULT_VALUE_EXTENDED = "1"
    	    }
    
    	    private val chartRetrofit by lazy {
    	        getRetrofit(HOST_SIMULATOR, ChartAPI::class.java)
    	    }
    
    	    ...
    
    	    @SuppressLint("HardwareIds")
    	    override suspend fun fetchDataFeed(
    	            params: QuoteFeedParams,
    	            applicationId: String
    	    ): NetworkResult<List<OHLCParams>> {
    	        return try {
    	            chartRetrofit
    	                    .fetchDataFeedAsync(
    	                            params.symbol,			// IBM
    	                            params.start,			// 2019-10-08T04:00:00.000Z
    	                            params.end,			// 2021-05-19T18:14:05.200Z
    	                            params.interval,		// day
    	                            params.period?.toString(),	// 1
    	                            DEFAULT_VALUE_EXTENDED,
    	                            applicationId
    	                    )
    	                    .safeExtractNetworkResult()
    	        } catch (e: IOException) {
    	            // The exception occurs when the internet connection is not stable
    	            NetworkResult.Failure(NetworkException(null, 3000))
    	        }
    	    }
    
    	    private fun <T> getRetrofit(baseUrl: String, api: Class<T>): T {
    	        return Retrofit.Builder()
    	                .baseUrl(baseUrl)
    	                .addCallAdapterFactory(CoroutineCallAdapterFactory())
    	                .addConverterFactory(GsonConverterFactory.create())
    	                .build()
    	                .create(api)
    	    }
    
    	    ...
    
    	}
    
  4. With the data feed in place, you now need a way to stop requesting data. Normally, the example quotefeeds provided in our library package do this by setting a moreAvailable flag to tell the quotefeed to retrieve more data depending on the circumstance. The moreAvailable flag is also available within this project, but it is accessible within the mobile code itself instead of in our ChartIQ library or native-sdk template. As a developer, you have full control over how to determine when you want to stop retrieving historical data. You can look at the pullInitialData, pullUpdate, and pullPagination methods in ChartIQHandler.kt for reference. Note that pullUpdateData always sets moreAvailable to false since updates use a continuous pooling interval to ensure the chart always displays the most current data.

    	@JavascriptInterface
        override fun pullInitialData(
        ...
        ) {
            ...
                callbackId?.let {
                    // set moreAvailable to 'true' if your feed has more data to
                    // return after the initial pull. Otherwise, set to 'false'.
                    invokePullCallback(callbackId, data, true)
                }
            }
        }
    
        override fun pullUpdateData(
        ...
        ) {
            ...
                callbackId?.let {
                    // just an update, no need to see if there is more historical
                    // data available
                    invokePullCallback(callbackId, data, false)
                }
            }
        }
    
        override fun pullPaginationData(
        ...
        ) {
            ...
                callbackId?.let {
                    // Check to see if you need to try and retrieve more historical data.
                    // This is where you can put your own logic on when to stop retrieving
                    // historical data.
                    // By default if the last pagination request return 0 data then it has
                    // probably reached the end.
                    // If you have spotty data then another idea might be to check the last
                    // historical date, this would require you knowing what date to stop at.
                    var moreAvailable = true
                    if(data.size < 1) moreAvailable = false
                    invokePullCallback(callbackId, data, moreAvailable)
                }
            }
        }
    
  5. The ChartIQ SDK also provides a listener that will tell the native Android side that the chart has finished rendering in the WebView. The reason for this is when the WebView is loaded the native Android code thinks everything is done loading when in reality the chart might still be processing. The chartAvailable listener ensures that you can start to modify the chart with no chance of interference or strange loading artifacts. By default, we have it set in the init method in MainViewModel.kt, but feel free to place this call wherever you see fit.

    	init {
            chartIQ.apply {
                addChartAvailableListener { chartAvailable ->
    	            if(chartAvailable) {
    	                // chart has been loaded, now call what you want
    	                // chartIQ.setChartType(ChartType.MOUNTAIN)
    	                // chartIQ.setSymbol("IBM")
    	                // and so on...
    				}
    			}
    		}
    	}
    

Now we're ready to deploy the ChartIQ Android SDK.

Deploy the ChartIQ mobile SDK

  1. Deploy the mobile SDK so it can be used by the application.

    • Copy sample-template-native-sdk.html from the chartiq/mobile directory into the root directory of the ChartIQ library package you were provided.

    • In the template script, set the value of the displayDataDisclaimer variable to true if the app uses simulated data; to false, if the app uses production data.

    • Make sure DEFAULT_CHART_URL is set to the path where your ChartIQ HTML5 library is deployed so the WebView can be initialized. For the sample application, the path is set in BuildConfig in the build.gradle file in the demo directory.

    • Note: If you are deploying your app using localhost, it is important to know that you have to use your local machine IP address for the URL path. Do not use "localhost" or "127.0.0.1", as the Android emulator or real device won't recognize that path because the app is technically on its own device.

      android {
          // ...
          defaultConfig {
              // !!!!! adjust `deploypath` as needed to match the path
              // to get to sample-template-native-sdk.html
              buildConfigField("String", "DEFAULT_CHART_URL", "\"http://deploypath/sample-template-native-sdk.html\"")
          }
      }
      

    Loading sample-template-native-sdk.html as a local resource

    By default, the sample app is configured to load the sample HTML template and corresponding library files remotely via HTTP.

    If instead you want to load the library files as local resources, you'll need to ensure that the files can be found by the app. We recommended you use WebViewAssetLoader.

    Alternatively, files can also be loaded using the file:/// scheme, but you will need to bundle the app first to abide by Cross-Origin Resource Sharing (CORS) rules. You can do this using webpack or another module bundler. We include a webpack build specifically for the mobile project in your ChartIQ library package. The steps to create your own bundle are as follows:

    1. Make any necessary changes to chartiq/webpack-example/webpack.config.mobile.js and chartiq/webpack-example/src/sample-template-native-sdk-webpack.js.
    2. Execute npm run build:mobile in the chartiq/webpack-example folder of your library package. The script produces an ES5 bundle which can be used to load files using the file:/// scheme.
    3. A new folder named dist is created in the webpack-example folder; dist contains your bundled library.
    4. By default, the template file is dist/index.html. Change the file name if needed.
    5. Import the dist folder locally into your mobile project. Follow the necessary steps to access index.html

    Note: If you are planning on bundling the library with your application, please let us know so we can send you a suitable package. The standard domain locked library will not work in this case.

    See Advantages of remote deployment for more information.

  2. Build and run the app in an emulator or physical device. You should see a ChartIQ view loaded and populated with a chart.

Data Integration Overview

There are multiple ways to provide your chart with data, but the most common in our ChartIQ library is the Pull and Push integrations. Below are the basic steps you need in order to populate your WebView chart with data for each integration. If you want in-depth details of Pull and Push, refer to the Data Integration Overview tutorial.

Pull Data - The WebView chart requests data from the application via a quotefeed. The example in Create a ChartIQ View is an example of Pulling data.

  1. By default, the sample-template-native-sdk.html template already has a quotefeed setup in order to receive data from the mobile application. There really shouldn't be a need to modify this functionality as it's just a process that processes the data that is sent by the application to the chart and sends the necessary quotefeed parameters back to the application (startdate, enddate, etc). If you do need to modify this setup for some reason you can do so in sample-template-native-sdk.html and mobile/nativeSdkBridge.js located in your ChartIQ package that was provided to you.

  2. The refreshInterval for the quotefeed determines how long to wait before requesting updates. By default the value is set to 1 second. You cannot change this value from your mobile application as making modifications to the quotefeed after it has been created can lead to questionable behavior. You can only change this value in your sample-template-native-sdk.html template or in your js/defaultConfiguration.js file.

    	// sample-template-native-sdk.html
    	// modify before you call config.createChart
    	config.quoteFeeds[0].behavior.refreshInterval = 10 // 10 second interval
    
    	or
    
    	// js/defaultConfiguration.js
    	quoteFeeds: [
    		{
    			quoteFeed: resources.quoteFeed,
    			behavior: { refreshInterval: 10, bufferSize: 200 }, // 10 second interval
    			// filter: () => {}
    		}
    	]
    
  3. Make sure your mobile application is ready for the quotefeed requests. This involves making sure you have pullInitialData, pullUpdateData, and pullPaginationData available in your application. See step 2 in the Create a ChartIQ View example.

  4. Give your application access to data. Usually, this is a URL with the necessary parameters to a service that you get your data from. Access to our quotefeed simulator is delivered out of the box and provides an easy way to see if your chart is working. The simulator provides fake data so you will want to switch this as soon as you can. Once you need to make the switch just change the URL located in network/ChartIQNetworkManager.kt.

Push Data - The mobile application sends data to the WebView chart. This can be done in a number of ways. You can statically load data or have it stream to your application. Essentially, you are now the quotefeed and responsible for all its data, the chart will never request data.

  1. The chart itself no longer needs a quotefeed, so you can just remove it completely. As with the changing the refreshInterval from the mobile application, this step is only accessible if you change it directly in sample-template-native-sdk.html

    	const config = getDefaultConfig({
    		markerSample: marker.MarkersSample,
    		scrollStyle: PerfectScrollbar,
    		//quoteFeed: quotefeed,	// a blank chart will now load
    		nameValueStore: CIQ.NameValueStore
    	});
    
  2. You will need to set the data method for the mobile application to Push mode in the init method located in MainViewModel.kt.

    	init {
     		chartIQ.apply {
    			start {
    	             	chartIQ.setDataMethod(DataMethod.PUSH, "")
    			}
    		}
    	}
    
  3. Technically you can also remove the code in the mobile application that deals with a quotefeed. That is up to you if you so wish.

  4. Once the chart is ready to receive data you can now Push data via the mobile SDK. You will need to pass a List object to the chart.

    	init {
    		chartIQ.apply {
    			// ensure chart is ready
    	    		addChartAvailableListener { chartAvailable ->
             			if(chartAvailable) {
             			val data = yourWayToGetData() // where data is a List<OHLCParams>
                        	chartIQ.pushData(data)
                    	}
            		}
    		}
    	}
    

Pull/Push Hybrid - There is a common use case where a user wants both data integrations for their application. You might want Pull to retrieve all your historical data and Push for data updates. You basically just combine the methods outlined above with a couple of tweaks.

  1. Set your quotefeed refreshInteval to 0 in sample-template-native-sdk.html or js/defaultConfiguration.js. The quotefeed will no longer request updates, but it will still request historical data.

  2. Set your data method to Push in your mobile application

    	// MainViewModel.kt
    	init {
    		chartIQ.apply {
    	         start {
    	             	chartIQ.setDataMethod(DataMethod.PUSH, "")
    			}
    		}
    	}
    
  3. Leave all your quotefeed functionality in your mobile application and setup a call to get your Push data.

    	init {
    		chartIQ.apply {
    			// ensure chart is ready
    			addChartAvailableListener { chartAvailable ->
    				if(chartAvailable) {
    					val data = yourWayToGetData() // where data is a List<OHLCParams>
                        	chartIQ.pushData(data)
    				}
    			}
    		}
    	}
    
  4. That's it! Your chart will now request historial data using the quotefeed, and any updates will be handled via your own streaming service.

Extend the ChartIQ mobile SDK

So now that you have the chart working, it will be useful to know how to extend the the mobile SDK. A simple example of how to add your own function to the nativeSdkBridge.js file is in the Getting Started on Mobile tutorial, but how does the Android native code call the JavaScript functions? The Android Webview has a native method, executeJavascript, that takes a string that represents the call you want to make in JavaScript. The following example uses the files that come with the Android mobile SDK and ChartIQ SDK.

Let's say you want a method that returns the series object that represents all the series that are currently drawn on the chart.

  1. First modify your nativeSdkBridge.js file which is packaged with your ChartIQ SDK (chartiq/mobile/nativeSdkBridge.js).

    CIQ.MobileBridge.getAllSeries = function () {
        // clone the object if you plan on modifying any of the fields before passing back to Android
        const allSeries = CIQ.clone(stxx.chart.series);
        // convert to a string first if you are passing back an object
        return JSON.stringify(seriesObj);
    };
    
  2. Now add a wrapper method to ChartIQHandler.kt. Since we are returning a value, we need to use the evaluateJavaScriptWithReturn method.

    override fun getAllSeries(callback: OnReturnCallback<List<Series>>) {
         val script = "CIQ.MobileBridge.getAllSeries();"
         executeJavascript(script) {
             // do what you want with the return data
             val objectResult = Gson().fromJson(it, Object::class.java)
             callback.onReturn(objectResult)
         }
    

    Alternatively you can call the chart engine JavaScript object (stxx in the example below) directly from the Android side. This is not encouraged as putting a helper method in the native SDK bridge script allows for easier debugging and less confusion when one script is providing a layer of abstraction.

    override fun getAllSeries(callback: OnReturnCallback<List<Series>>) {
         val script = "stxx.chart.series;" // not encouraged
         executeJavascript(script) {
             // do what you want with the return data
             val objectResult = Gson().fromJson(it, Object::class.java)
             callback.onReturn(objectResult)
         }
     }
    
  3. This new Android method can now be called by the ChartIQ object.

    private fun messingWithSeries() {
        // series business
        val allTheSeries = chartIQ.getAllSeries()
        // now do what you want with the series data
    }
    

The ability to extend the ChartIQ mobile SDK is powerful, as it gives you access to all the functions that the ChartIQ SDK uses. We cannot one-to-one map all the ChartIQ functions, as that would create a bridge file much too large, but if there are certain functions you absolutely need, we encourage you to extend them in the native SDK bridge.

Next steps

See the following: