Я разрабатываю приложение для 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: // локальный / книги в браузере я получаю следующий результат:
{"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();
?>
А также выключите брандмауэр.
Хорошего дня, ребята! 🙂
Других решений пока нет …