Search code examples
phpandroidmysqlhttpurlconnectionstringbuilder

How to optimize getting data from mysql via php / android?


Introduction

I have an app and want to force the user to update it, if a new version is at the google play market. This is working fine with the following code but is not very stable. I am doing it via AsyncTask and getting data from the php file. But it gives me a feeling that there must be a better way or a way that makes it much more stable.

Question

How can I set a timeout to the procedure, for example because of a very low internetconnection from the user?

Code

get_newest_apk.php

<?PHP

    /*  GET APK VERSION FROM ANDROID DEVICE
        Example: [PATH]/get_newest_apk.php?apkversion=6
    */
    if($_GET["apkversion"]){
        $apkversion= $_GET["apkversion"];

        //MYSQL LOGIN PARAMETERS
        $host = '*****';
        $user = '*****';
        $pass = '*****';
        $db =   '*****';

        $mysqli = new mysqli($host, $user, $pass, $db);

            $result = $mysqli->query("SELECT MAX(VERSION) FROM TBL_APK");
            $row = $result->fetch_row();
            $count = $row[0];

            if($count > $apkversion){
                //Newer APK is avaiable
                echo "1";
            }else{
                //There is no never APK avaiable
                echo "2";
            }

    }else{
        //Error by GETTING apkversion from Android device
        echo "3";
    }
?>

AsyncTask Class

class checkForNewAPK extends AsyncTask<Void, Void, String> {
    @Override
    protected void onPreExecute() {
        //Do not show the user a progress because he don't want to see it in every onResume
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        int intResult = Integer.parseInt(s);

        //strResult as intResult; 1 = Newer APK avaiable, 2 = No newer APK avaiable, 3 = Error at $_GET["apkversion"] line 6
        if(intResult == 1){
            //Force to Update App
            Log.v("APKResult: ", "1");
        }else if(intResult == 2){
            //No update needed
            Log.v("APKResult: ", "2");
        }else if(intResult == 3){
            //Error in PHP-File
            Log.v("APKResult: ", "3");
        }else{
            //Unknown error
            Log.v("APKResult: ", "Unkown Error");
        }
    }

    //in this method we are fetching the json string
    @Override
    protected String doInBackground(Void... voids) {
        try {
            int intApkVersion = getApplication().getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
            URL url = new URL(strUrlGetNewestAPK+"?apkversion="+intApkVersion);
            String strResultFromEcho;

            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            StringBuilder strResult = new StringBuilder();

            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            while ((strResultFromEcho = bufferedReader.readLine()) != null) {
                strResult.append(strResultFromEcho + "\n");
            }

            return strResult.toString().trim();
        } catch (Exception e) {
            return null;
        }
    }
}

Solution

  • How can I set a timeout to the procedure, for example because of a very low internetconnection from the user?

    You need to use setConnectTimeout and setReadTimeout

    setConnectTimeout

    • Sets a specified timeout value, in milliseconds, to be used when opening a communications link to the resource referenced by this URLConnection. If the timeout expires before the connection can be established, a java.net.SocketTimeoutException is raised. A timeout of zero is interpreted as an infinite timeout.

    setReadTimeout

    • Sets the read timeout to a specified timeout, in milliseconds. A non-zero value specifies the timeout when reading from Input stream when a connection is established to a resource. If the timeout expires before there is data available for read, a java.net.SocketTimeoutException is raised. A timeout of zero is interpreted as an infinite timeout.

    SAMPLE CODE

       HttpURLConnection con = (HttpURLConnection) url.openConnection();
       con.setConnectTimeout(3000); //set connection time out in milliseconds
       con.setReadTimeout(3000); // set read time out in milliseconds
    

    Make below changes in your code

    class checkForNewAPK extends AsyncTask<Void, Void, String> {
        @Override
        protected void onPreExecute() {
            //Do not show the user a progress because he don't want to see it in every onResume
        }
    
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            int intResult = Integer.parseInt(s);
    
            //strResult as intResult; 1 = Newer APK avaiable, 2 = No newer APK avaiable, 3 = Error at $_GET["apkversion"] line 6
            if(intResult == 1){
                //Force to Update App
                Log.v("APKResult: ", "1");
            }else if(intResult == 2){
                //No update needed
                Log.v("APKResult: ", "2");
            }else if(intResult == 3){
                //Error in PHP-File
                Log.v("APKResult: ", "3");
            }else{
                //Unknown error
                Log.v("APKResult: ", "Unkown Error");
            }
        }
    
        //in this method we are fetching the json string
        @Override
        protected String doInBackground(Void... voids) {
            try {
                int intApkVersion = getApplication().getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
                URL url = new URL(strUrlGetNewestAPK+"?apkversion="+intApkVersion);
                String strResultFromEcho;
    
                HttpURLConnection con = (HttpURLConnection) url.openConnection();
                con.setConnectTimeout(3000); //set connection time outt in milliseconds
                con.setReadTimeout(3000); // set read time outt in milliseconds
    
                StringBuilder strResult = new StringBuilder();
    
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
                while ((strResultFromEcho = bufferedReader.readLine()) != null) {
                    strResult.append(strResultFromEcho + "\n");
                }
    
                return strResult.toString().trim();
            } catch (SocketTimeoutException e) {
                // this block code execute when time out exception is occur
                // you need to perform your logic here when time out exception occur
                return "Request timeout occur.\nTap on \'TRY AGAIN\' to retry";
            }
        }
    }
    

    Note : You can also use library for API Calling

    You can use Volley library

    • Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster. Volley is available on GitHub.

    FROM DOCS

    Volley offers the following benefits:

    • Automatic scheduling of network requests.

    • Multiple concurrent network connections.

    • Transparent disk and memory response caching with standard HTTP cache coherence. Support for request prioritization.

    • Cancellation request API. You can cancel a single request, or you can set blocks or scopes of requests to cancel.

    • Ease of customization, for example, for retry and backoff.

    • Strong ordering that makes it easy to correctly populate your UI with data fetched asynchronously from the network.

    • Debugging and tracing tools.

    You can use Retrofit library

    Retrofit vs Volley

    Please read this post Comparison of Android networking libraries: OkHTTP, Retrofit, and Volley