将Retrofit与HTML一起使用时出现JSON错误

时间:2017-04-01 21:35:17

标签: php android html json retrofit

当我从index.php中删除HTML代码并且只保留php行之间时,我的代码工作正常。但是当我使用HTML行显示的时候 - 我需要应用程序的其他部分 - 它会给出错误:

“使用JsonReader.setLenient(true)接受第1行第1行路径上格式错误的JSON $”

我尝试过使用

Gson gson = new GsonBuilder()
            .setLenient()
            .create();

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(Constants.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

但它给了我另一个错误:

“java.lang.IllegalStateException:预期BEGIN_OBJECT但在第1行第1行路径为STRING”

这是我的Logcat output

如何解决这个问题?!!!

FirstPOIPreference.java:

public class FirstPOIPreference extends DialogPreference {

private EditText et_alias, et_keyword, et_address;
private Spinner sp_city;
private ArrayAdapter<String> adapter;
private boolean deleted;
private Context context;
private SharedPreferences pref;
private POI poiDialog = new POI();

public FirstPOIPreference(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
    init();
}

private void init() {
    setPersistent(false);
    setDialogLayoutResource(R.layout.pref_poi_dialog);
    setPositiveButtonText(android.R.string.ok);
    setNegativeButtonText(android.R.string.cancel);
}

@Override
protected void onBindDialogView(View view) {
    super.onBindDialogView(view);
    pref = PreferenceManager.getDefaultSharedPreferences(this.context);
    load(getSharedPreferences());
    initViews(view);
    fillViews();
}

private void load(SharedPreferences prefs) {
    poiDialog.setAlias(prefs.getString(Constants.FIRST_POI_ALIAS, ""));
    poiDialog.setKeyword(prefs.getString(Constants.FIRST_POI_KEYWORD, ""));
    poiDialog.setAddress(prefs.getString(Constants.FIRST_POI_ADDRESS, ""));
    poiDialog.setCity((prefs.getString(Constants.FIRST_POI_CITY, "")));
}

private void initViews(View view) {
    deleted = false;
    TextView tv_delete = (TextView) view.findViewById(R.id.tv_poi_delete);
    et_alias = (EditText) view.findViewById(R.id.et_poi_alias);
    et_keyword = (EditText) view.findViewById(R.id.et_poi_keyword);
    et_address = (EditText) view.findViewById(R.id.et_poi_address);
    sp_city = (Spinner) view.findViewById(R.id.spinner_poi_city);
    sp_city.setPrompt("City");
    String[] arrayCity = new String[]{"Erie", "Pittsburgh", "Cleveland", "Buffalo", "Niagara Falls", "Jamestown"};
    adapter = new ArrayAdapter <> (this.getContext(),
            android.R.layout.simple_spinner_dropdown_item, arrayCity);
    sp_city.setAdapter(adapter);

    et_alias.addTextChangedListener(new TextWatcher() {

        public void afterTextChanged(Editable s) {
            poiDialog.setAlias(et_alias.getText().toString());
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }
    });

    et_keyword.addTextChangedListener(new TextWatcher() {

        public void afterTextChanged(Editable s) {
            poiDialog.setKeyword(et_keyword.getText().toString());
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }
    });

    et_address.addTextChangedListener(new TextWatcher() {

        public void afterTextChanged(Editable s) {
            poiDialog.setAddress(et_address.getText().toString());
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }
    });

    sp_city.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView <?> parentView, View selectedItemView,
                                   int position, long id) {
            poiDialog.setCity(sp_city.getSelectedItem().toString());
        }

        @Override
        public void onNothingSelected(AdapterView <?> parentView) {
        }
    });

    tv_delete.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            AlertDialog.Builder delete_builder = new AlertDialog.Builder(context);
            delete_builder.setMessage("Are you sure you want to delete this point of interest?")
                    .setCancelable(false)
                    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Toast.makeText(context, "Deleting POI !", Toast.LENGTH_LONG).show();
                            deletePOI();
                        }
                    })
                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                        }
                    });
            AlertDialog alertDelete = delete_builder.create();
            alertDelete.setTitle("Delete POI!");
            alertDelete.show();
        }
    });
}

private void fillViews() {
    et_alias.setText(poiDialog.getAlias());
    et_keyword.setText(poiDialog.getKeyword());
    et_address.setText(poiDialog.getAddress());
    sp_city.setSelection(adapter.getPosition(poiDialog.getCity()));
}

@Override
protected void onDialogClosed(boolean positiveResult) {
    if (positiveResult) {
        String alias, keyword, address, city;
        if(deleted) {
            et_alias.setText("");
            et_keyword.setText("");
            et_address.setText("");
            sp_city.setPrompt("City");
        } else {
            alias = et_alias.getText().toString();
            keyword = et_keyword.getText().toString();
            address = et_address.getText().toString();
            city = sp_city.getSelectedItem().toString();
            if (!keyword.isEmpty() && !address.isEmpty() && !city.isEmpty()) {
                Toast.makeText(context, "Saving POI !", Toast.LENGTH_LONG).show();
                addPOI(alias, keyword, address, city);
            } else {
                Toast.makeText(context, "Required Fields are empty !", Toast.LENGTH_LONG).show();
            }
        }
    }
}

private void addPOI(String alias, String keyword, String address, String city) {
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(interceptor)
            .retryOnConnectionFailure(true)
            .connectTimeout(15, TimeUnit.SECONDS)
            .build();

    Gson gson = new GsonBuilder()
            .setLenient()
            .create();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(Constants.BASE_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

    RequestInterface requestInterface = retrofit.create(RequestInterface.class);

    User user = new User();
    user.setEmail(pref.getString(Constants.USER_EMAIL, ""));

    POI poi = new POI();
    poi.setAlias(alias);
    poi.setKeyword(keyword);
    poi.setAddress(address);
    poi.setCity(city);

    ServerRequest request = new ServerRequest();
    request.setOperation(Constants.ADD_POI);
    request.setUser(user);
    request.setPoi(poi);

    Call <ServerResponse> response = requestInterface.operation(request);
    response.enqueue(new Callback <ServerResponse>() {
        @Override
        public void onResponse(Call <ServerResponse> call,
                               retrofit2.Response <ServerResponse> response) {
            ServerResponse resp = response.body();
            if(resp.getResult().equals(Constants.SUCCESS)) {
                Toast.makeText(context, resp.getMessage(), Toast.LENGTH_LONG).show();
                SharedPreferences.Editor editor = getEditor();
                save(editor);
            } else {
                Toast.makeText(context, resp.getMessage(), Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Call <ServerResponse> call, Throwable t) {
            Log.d(Constants.TAG, "failed");
            Toast.makeText(context, t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
        }
    });
}

private void save(SharedPreferences.Editor editor) {
    editor.putString(Constants.FIRST_POI_ALIAS, poiDialog.getAlias());
    editor.putString(Constants.FIRST_POI_KEYWORD, poiDialog.getKeyword());
    editor.putString(Constants.FIRST_POI_ADDRESS, poiDialog.getAddress());
    editor.putString(Constants.FIRST_POI_CITY, poiDialog.getCity());
    editor.apply();
}

private void deletePOI() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(Constants.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    RequestInterface requestInterface = retrofit.create(RequestInterface.class);

    User user = new User();
    user.setEmail(pref.getString(Constants.USER_EMAIL, ""));

    POI poi = new POI();
    poi.setKeyword(pref.getString(Constants.FIRST_POI_KEYWORD, ""));
    poi.setCity(pref.getString(Constants.FIRST_POI_CITY, ""));

    ServerRequest request = new ServerRequest();
    request.setOperation(Constants.DELETE_POI);
    request.setUser(user);
    request.setPoi(poi);

    Call <ServerResponse> response = requestInterface.operation(request);
    response.enqueue(new Callback <ServerResponse>() {
        @Override
        public void onResponse(Call <ServerResponse> call,
                               retrofit2.Response <ServerResponse> response) {

            ServerResponse resp = response.body();
            if(resp.getResult().equals(Constants.SUCCESS)) {
                Toast.makeText(context, resp.getMessage(), Toast.LENGTH_LONG).show();
                SharedPreferences.Editor editor = getEditor();
                saveDelete(editor);
                deleted = true;
            } else {
                Toast.makeText(context, resp.getMessage(), Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Call <ServerResponse> call, Throwable t) {
            Log.d(Constants.TAG, "failed");
            Toast.makeText(context, t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
        }
    });
}

private void saveDelete(SharedPreferences.Editor editor) {
    editor.putString(Constants.FIRST_POI_ALIAS, "");
    editor.putString(Constants.FIRST_POI_KEYWORD, "");
    editor.putString(Constants.FIRST_POI_ADDRESS, "");
    editor.putString(Constants.FIRST_POI_CITY, "");
    editor.apply();
}

}

的index.php:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <pre>
        <?php

        // dispaly all errors except Warnings
        ini_set('display_errors',1);
        error_reporting(E_ALL & ~E_WARNING);

        include 'fetch_data.php';
        require_once 'users/login.php';
        require_once 'preferences/preferences.php';
        require_once 'include/functions_validation.php';

        $login = new Login();
        $pref = new Preferences();
        $fun = new FunctionsValidation();

        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            $data = json_decode(file_get_contents("php://input"));

            if(isset($data -> operation)) {
                $operation = $data -> operation;
                if(!empty($operation)) {
                    /*
                    * User registration and login operations
                    */
                    if($operation == 'register') {
                        echo $login -> register($data);
                    }
                    else if ($operation == 'regVerify') {
                        echo $login -> registerVerify($data);
                    }
                    else if ($operation == 'login') {
                        echo $login -> login($data);
                    }
                    else if ($operation == 'chgPass') {
                        echo $login -> changePassword($data);
                    }
                    else if ($operation == 'resPassReq') {
                        echo $login -> resetPasswordReq($data);
                    }
                    else if ($operation == 'resPass') {
                        echo $login -> resetPassword($data);
                    }
                    /*
                     * Point of Interest operations
                     */
                    else if($operation == 'addPOI') {
                        echo $pref -> addPOI($data);
                    }
                    else if($operation == 'deletePOI') {
                        echo $pref -> deletePOI($data);
                    }

                    /**
                     * Mileage Distance operations
                     */
                    else if($operation == 'addMileage') {
                        echo $pref -> addMileage($data);
                    }
                    else if($operation == 'deleteMileage') {
                        echo $pref -> deleteMileage($data);
                    }
                } else { // if operation is empty
                    echo $fun -> getMsgParamNotEmpty();
                }
            } else { // if operation is not set
                echo $fun -> getMsgInvalidParam();
            }
        } else if ($_SERVER['REQUEST_METHOD'] == 'GET') {
            echo "GeolocationNews API";
        }
        ?>
      </pre>
  </body>
</html>

1 个答案:

答案 0 :(得分:0)

Constants.BASE_URL是否指向您的index.php页面?

如果是这样,您正在尝试将HTML页面解析为JSON,这是无效的。我建议您从Android应用程序发送某种查询参数,您可以从PHP检查,以便HTML部分不包含在输出中。

假设您的Android应用程序将请求提交给index.php?output=json,例如。然后在index.php中,您可以检查:

<?php
$jsonOnly = (isset($_GET['output']) && $_GET['output'] == 'json');

if (!$jsonOnly):
?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <pre>
<?php
endif;

// your existing PHP code here

if (!$jsonOnly):
?>
    </pre>
</body>
</html>
<?php
endif;
?>

编辑但是,我认为将逻辑与演示文稿分开会更好。如果您将所有PHP代码放在单独的文件中,例如handle_request.php?然后在index.php中,您可以拥有所有HTML代码,然后包含该文件:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <pre>
        <?php include('handle_request.php'); ?>
    </pre>
</body>
</html>

对于您的应用,您可以创建一个用作Constants.BASE_URL的其他文件,例如app.php,它只会设置正确的JSON内容类型标头并包含相同的文件:< / p>

<?php
header('Content-Type: application/json');
include('handle_request.php');
?>