繁体   English   中英

消费使用Retrofit在Android中使用PHP和MySQL开发的RESTful API

[英]Consuming RESTful API developed in PHP and MySQL in Android using Retrofit

我正在开发一个Android应用程序,以使用改造功能访问REST API。

该API在PHP和MySQL中。

PHP文件如下:

index.php

<?php 
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "bookdb";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT * FROM books";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    echo '{"books":[';

        $first = true; 
        while($row=$result->fetch_assoc()){
        //  cast results to specific data types

            if($first) {
                $first = false;
            } else {
                echo ',';
            }
            echo json_encode($row);
        }
        echo ']}'; 
} else {
    echo "0 results";
}
$conn->close();
?>

当我在浏览器中使用http:// localhost / books访问它时,得到以下结果:

{"books":[{"author":"Ash Maurya","categories":"process","lastcheckedout":null,"lastcheckedoutby":null,"publisher":"O'REILLY","title":"Running Lean","url":"\/books\/1","book_id":"1"}]}

这是预期的输出。

现在,我尝试使用Android中的改造功能来使用它:

BookListActivity.java

package com.example.android.taskapp;

import android.content.Context;
import android.database.Cursor;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.SimpleCursorAdapter;

import com.example.android.taskapp.api.ApiInterface;
import com.example.android.taskapp.model.Book;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import retrofit.Callback;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.Response;

public class BookListActivity extends AppCompatActivity {

static final String API_URL = "http://192.168.0.104:8080/books";
ListView books_listview;
RestAdapter restAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_book_list);
    books_listview = (ListView) findViewById(R.id.books_listview);

    restAdapter = new RestAdapter.Builder().setEndpoint(API_URL).build();
    ApiInterface methods = restAdapter.create(ApiInterface.class);

    Callback cb = new Callback() {
        @Override
        public void success(Object o, Response response) {
            List<Book> books = (List<Book>) o;
            //Log.v("BookListActivity", booksString);
            //TypeToken<List<Book>> token = new TypeToken<List<Book>>() {};
            //List<Book> books = new Gson().fromJson(booksString, token.getType());

            List<HashMap<String,Object>> bookMapList = new ArrayList<>();
            for(Book b: books){
                HashMap<String, Object> bookmap = new HashMap<>();

                try {
                    bookmap.put(b.getClass().getField("author").getName(),b.getAuthor());
                    bookmap.put(b.getClass().getField("categories").getName(),b.getCategories());
                    bookmap.put(b.getClass().getField("lastCheckedOut").getName(),b.getLastCheckedOut());
                    bookmap.put(b.getClass().getField("lastCheckedOutBy").getName(),b.getLastCheckedOutBy());
                    bookmap.put(b.getClass().getField("publisher").getName(),b.getPublisher());
                    bookmap.put(b.getClass().getField("title").getName(),b.getTitle());
                    bookmap.put(b.getClass().getField("url").getName(),b.getUrl());
                    bookMapList.add(bookmap);
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
            }
            SimpleAdapter adapter = new SimpleAdapter(getApplication(), bookMapList, R.layout.list_item_book,
                    new String [] {"title", "author"},new int [] {R.id.book_title, R.id.book_author});

            books_listview.setAdapter(adapter);
        }

        @Override
        public void failure(RetrofitError error) {
            Log.e("BookListActivity", error.getMessage() +"\n"+ error.getStackTrace());
            error.printStackTrace();
        }
    };
    methods.getBooks(cb);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_book_list, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

这是我的ApiInterface类:

ApiInterface.java

package com.example.android.taskapp.api;

import com.example.android.taskapp.model.Book;

import java.util.List;

import retrofit.Callback;
import retrofit.client.Response;
import retrofit.http.GET;
import retrofit.http.Path;

/**
 * Created by aagam shah on 8/25/2015.
 */
public interface ApiInterface {

    @GET("/index.php")
    void getBooks(Callback<List<Book>> cb);
}

执行时出现以下错误:

com.example.android.taskapp E/BookListActivity﹕ socket failed: EACCES (Permission denied)
retrofit.RetrofitError: socket failed: EACCES (Permission denied)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:395)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ at retrofit.Platform$Android$2$1.run(Platform.java:142)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ at java.lang.Thread.run(Thread.java:841)
08-27 12:59:02.855  10942-10942/com.example.android.taskapp W/System.err﹕ Caused by: java.net.SocketException: socket failed: EACCES (Permission denied)
08-27 12:59:02.865      822-856/? I/ActivityManager﹕ Displayed com.example.android.taskapp/.BookListActivity: +541ms
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at libcore.io.IoBridge.socket(IoBridge.java:587)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at java.net.PlainSocketImpl.create(PlainSocketImpl.java:202)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at java.net.Socket.checkOpenAndCreate(Socket.java:668)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at java.net.Socket.setSoTimeout(Socket.java:523)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.internal.http.SocketConnector.connectRawSocket(SocketConnector.java:159)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.internal.http.SocketConnector.connectCleartext(SocketConnector.java:67)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.Connection.connect(Connection.java:152)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.Call.getResponse(Call.java:273)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:230)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:201)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at com.squareup.okhttp.Call.execute(Call.java:81)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at retrofit.client.OkClient.execute(OkClient.java:53)
08-27 12:59:02.865  10942-10942/com.example.android.taskapp W/System.err﹕ at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)

methods.getBooks(cb); 这条线。

谁能告诉我我错过了什么?

我已经尝试寻找类似的答案,但是它们没有帮助。

我还在应用程序节点上方的清单中包含了所有必要的权限。

非常感谢您的帮助。

经过四处探索,终于找到了解决我问题的方法:

我错过的最大的事情是:

<uses-permission android:name="ANDROID.PERMISSION.INTERNET" />

它应该是

<uses-permission android:name="android.permission.INTERNET" />

其他文件中有一些小的更改:

BookListActivity.java

public class BookListActivity extends AppCompatActivity {

static final String API_URL = "http://192.168.0.104/books";
ListView books_listview;
RestAdapter restAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_book_list);
    books_listview = (ListView) findViewById(R.id.books_listview);

    OkHttpClient mOkHttpClient = new OkHttpClient();
    mOkHttpClient.setConnectTimeout(15000,TimeUnit.MILLISECONDS);
    mOkHttpClient.setReadTimeout(15000,TimeUnit.MILLISECONDS);

    restAdapter = new RestAdapter.Builder()
            .setEndpoint(API_URL)
            .setClient(new OkClient(mOkHttpClient))
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .build();
    ApiInterface methods = restAdapter.create(ApiInterface.class);

    Callback<List<Book>> cb = new Callback<List<Book>>() {
        @Override
        public void success(List<Book> books, Response response) {
            //Log.v("BookListActivity", booksString);
            //TypeToken<List<Book>> token = new TypeToken<List<Book>>() {};
            //List<Book> books = new Gson().fromJson(booksString, token.getType());

            List<HashMap<String,Object>> bookMapList = new ArrayList<>();
            for(Book b: books){
                HashMap<String, Object> bookmap = new HashMap<>();

                try {

                    bookmap.put(b.getClass().getField("book_id").getName(),b.getBook_id());
                    bookmap.put(b.getClass().getField("author").getName(),b.getAuthor());
                    bookmap.put(b.getClass().getField("categories").getName(),b.getCategories());
                    bookmap.put(b.getClass().getField("lastCheckedOut").getName(),b.getLastCheckedOut());
                    bookmap.put(b.getClass().getField("lastCheckedOutBy").getName(),b.getLastCheckedOutBy());
                    bookmap.put(b.getClass().getField("publisher").getName(),b.getPublisher());
                    bookmap.put(b.getClass().getField("title").getName(),b.getTitle());
                    bookmap.put(b.getClass().getField("url").getName(),b.getUrl());
                    bookMapList.add(bookmap);
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
            }
            SimpleAdapter adapter = new SimpleAdapter(getApplication(), bookMapList, R.layout.list_item_book,
                    new String [] {"title", "author"},new int [] {R.id.book_title, R.id.book_author});

            books_listview.setAdapter(adapter);
        }

        @Override
        public void failure(RetrofitError error) {
            Log.e("BookListActivity", error.getMessage() +"\n"+ error.getStackTrace());
            error.printStackTrace();
        }
    };
    methods.getBooks(cb);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_book_list, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

和index.php

<?php 
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "bookdb";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT * FROM books";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    echo '[';

        $first = true; 
        while($row=$result->fetch_assoc()){
        //  cast results to specific data types

            if($first) {
                $first = false;
            } else {
                echo ',';
            }
            echo json_encode($row);
        }
        echo ']'; 
} else {
    echo "0 results";
}
$conn->close();
?>

并关闭防火墙。 祝你有美好的一天,费拉斯! :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM