Fadly Dzil
Fadly Dzil

Reputation: 2226

AlertDialog.Builder shows null from API Request

I am starting to learn to develop an android app (hopefully I can understand this awesome technology).

I have a Rest API that I build myself with PHP.

The case is, the android app scan a QR-Code and then send the resultScan to my Rest API.

Here is my code:

import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.google.zxing.Result;
import me.dm7.barcodescanner.zxing.ZXingScannerView;
import org.json.JSONObject;



public class InfoCoilActivity extends AppCompatActivity implements ZXingScannerView.ResultHandler {
    private static final int REQUEST_CAMERA = 1;
    private ZXingScannerView scannerView;
    private String responseResult;

    @Override
    public void handleResult(Result result) {
        final String scanResult = result.getText();
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Result Scan For Info Coil");
        builder.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                scannerView.resumeCameraPreview(InfoCoilActivity.this);
            }
        });
        builder.setMessage("Result " + handleRequestApi(scanResult));
        AlertDialog alert = builder.create();
        alert.show();
    }

    public String handleRequestApi(String textCode) {
        String URL = "http://my-web.com/api/morowali-coil/" + textCode;
        final RequestQueue requestQueue = Volley.newRequestQueue(this);

        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
                Request.Method.GET,
                URL,
                null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        responseResult = response.toString();
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        responseResult = error.toString();
                    }
                }
        );
        requestQueue.add(jsonObjectRequest);
        return responseResult;
    }
}

Please see in builder.setMessage("Result " + handleRequestApi(scanResult)); When I scan the qr code in first shot, I got message

Result null

I try to see in logcat, in the first shot, successfully get the response json like this:

10-17 14:07:01.492 11568-11568/com.dzil.myapplication E/Rest Response:: {"id":889,"coil_number":"QLZ18K01014A","planning_delivery":"WAREHOUSE","billet_number":"Y180908B03-4","width":0,"thickness":"0.00","grade":"S30403","size":"1.84*1250*C","actual_size":"1.85*1249","quantity":1,"nett":20930,"gross":21016,"customer":"IIS","contract_number":"IRNC18\/CC1137","procurement_contract_number":"","white_roll_number":"N1809100738","production_date":"2018-09-21","standard_eksekutif":"EN 10028-7","order_number":"ET18\/CC708001-IIS","unstuffing_plan":"2018-10-14","length":1143,"production_warehouse":"6#库","port":"Surabaya","vessel":null,"vessel_id":2,"urut":889,"lokasi":null,"lokasi_terakhir":null,"nama_file":"Copy of morowali-surabaya-example-format-data","created_by":"1","updated_by":"1","created_at":"2018-10-12 16:09:46","updated_at":"2018-10-12 16:09:46"}

But when I try again in second shot, it normal that I got those json like json above

Result {"id":889,"coil_number":"QLZ18K01014A","planning_delivery":"WAREHOUSE","billet_number":"Y180908B03-4","width":0,"thickness":"0.00","grade":"S30403","size":"1.84*1250*C","actual_size":"1.85*1249","quantity":1,"nett":20930,"gross":21016,"customer":"IIS","contract_number":"IRNC18\/CC1137","procurement_contract_number":"","white_roll_number":"N1809100738","production_date":"2018-09-21","standard_eksekutif":"EN 10028-7","order_number":"ET18\/CC708001-IIS","unstuffing_plan":"2018-10-14","length":1143,"production_warehouse":"6#库","port":"Surabaya","vessel":null,"vessel_id":2,"urut":889,"lokasi":null,"lokasi_terakhir":null,"nama_file":"Copy of morowali-surabaya-example-format-data","created_by":"1","updated_by":"1","created_at":"2018-10-12 16:09:46","updated_at":"2018-10-12 16:09:46"}

Please advice!

Upvotes: 0

Views: 554

Answers (4)

Sina Khorshidian
Sina Khorshidian

Reputation: 332

This error is because of asynchronisity in using volley and alert dialog. You can create a custom interface like below code:

public interface VolleyResponseListener{
    void onVolleyResponse(String response);        
}

and use it in your codes.

public class InfoCoilActivity extends AppCompatActivity implements ZXingScannerView.ResultHandler, VolleyResponseListener {
    private static final int REQUEST_CAMERA = 1;
    private ZXingScannerView scannerView;
    private String responseResult;
    private VolleyResponseListener volleyResponseListener;

public interface VolleyResponseListener{
    void onVolleyResponse(String response);        
}

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        volleyResponseListener = (VolleyResponseListener) this;

        //... your codes...

    }

    @Override
    public void handleResult(Result result) {

        handleRequestApi(result.getText());

    }

    public void handleRequestApi(String textCode) {
        String URL = "http://my-web.com/api/morowali-coil/" + textCode;
        final RequestQueue requestQueue = Volley.newRequestQueue(this);

        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(
                Request.Method.GET,
                URL,
                null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        volleyResponseListener.onVolleyResponse(response.toString());
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        volleyResponseListener.onVolleyResponse(error.toString());
                    }
                }
        );
        requestQueue.add(jsonObjectRequest);
    }

    @Override
    public void onVolleyResponse(String response){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Result Scan For Info Coil");
        builder.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                scannerView.resumeCameraPreview(InfoCoilActivity.this);
            }
        });
        builder.setMessage("Result " + response);
        AlertDialog alert = builder.create();
        alert.show();
    }

}

Notice: I've add and remove some codes. Be carefull about implements and onCreate.

Upvotes: 0

Aaron
Aaron

Reputation: 3894

Your dialog was created immediately without waiting for the response because the function handleRequestApi(scanResult) was called asynchronously, therefore it showed null instead because the initial value of responseResult in your activity was null at the time.

To fix this, you should create the dialog only when it receives the response:

new Response.Listener<JSONObject>() {
    @Override
    public void onResponse(JSONObject response) {
        AlertDialog dialog = new AlertDialog.Builder(this)
            .setTitle(...)
            .setPositiveButton(...)
            .setMessage(response.toString())
            .create();
        dialog.show();
    }
}, ...

Upvotes: 1

Bruno
Bruno

Reputation: 4007

You can't do it like this because of asynchronism. The first shot returns null because the handleRequestApi() method does not have the response of the request. The second shot returns something because of cache.

To use asynchronism correctly, you have to manage your response directly in the onResponse() callback. You want to display an AlertDialog ? Do something like this

@Override
public void onResponse(JSONObject response) {
    responseResult = response.toString();
    AlertDialog.Builder builder = new AlertDialog.Builder(InfoCoilActivity .this);
    builder.setTitle("Result Scan For Info Coil");
    builder.setPositiveButton("Continue", new DialogInterface.OnClickListener() 
    {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            scannerView.resumeCameraPreview(InfoCoilActivity.this);
        }
    });
    builder.setMessage("Result " + response);
    AlertDialog alert = builder.create();
    alert.show();
}

Upvotes: 2

marmor
marmor

Reputation: 28229

handleRequestApi is an asynchronous method, meaning that it returns before getting any value from your API.

So return responseResult will always return the initial value of null.

see: Asynchronous vs synchronous execution, what does it really mean? for more information about asynchronous tasks

Upvotes: 2

Related Questions