我正在制作运行ASP.NET WebService的Android应用。 Webservice发送一个JSON对象,app解析该对象并在屏幕上显示。在一种情况下,JSON对象太大,我得到Failed Binder Transaction错误。我的解决方案是获取该JSON对象并将其嵌入到应用程序代码中,这样就不需要从服务器获取该JSON对象。你能告诉我能为这个问题做些什么吗? 或者,您能告诉我如何从Webservice获取该JSON对象吗?感谢。
答案 0 :(得分:12)
将大尺寸数据从服务器发送到移动设备。 JSON重量轻。 如果要使用更有效的方式传递数据,则将其传递给分页。 如果你想使用比JSON更轻的协议,那么实现下面的google协议,这些协议非常有用,它们支持主要语言。 下面是较小的序列化数据结构。谷歌的数据交换协议。
希望这对你有用。
答案 1 :(得分:4)
如果数据很大,那么尝试将其保存在数据库中,然后使用SQLite处理它。 (但如果动态,则不推荐)
要解析json对象,请使用gson或jackson。这有助于在部分解析json数据时显着降低内存消耗。 得到Gson,杰克逊在这里 https://sites.google.com/site/gson/gson-user-guide http://jackson.codehaus.org/
杰克逊的例子 http://www.mkyong.com/java/jackson-streaming-api-to-read-and-write-json/
答案 2 :(得分:2)
首先:如果您的代码中存在崩溃或异常,您可能希望发布该代码。 " Binder Exception失败"有点太模糊,无法理解你在做什么。
如果您真的想要发布内置JSON嵌入式Android应用程序(为了避免从服务器获取它,请考虑将其存储为资产并使用AssetManager访问它。您基本上删除了该文件应用程序资源文件夹中的json,并使用AssetManager读取它们。
如果您仍想从服务器下载并对其进行操作,请考虑使用流API来下载和解析JSON。 Android的JSONObject没有这样做,它坚持在解析之前将整个JSON字符串放在内存中。
如果您想直接从URL下载流式传输到流式解析器(例如GSON),请尝试沿着这些方向进行操作。首先从您尝试获取的URL中获取InputStream:
URL u = new URL(url);
URLConnection conn = u.openConnection();
InputStream is = new BufferedInputStream(conn.getInputStream());
然后将InputStream直接提供给您的流解析器。这应该可以防止在解析之前将整个响应拉入内存,但是您仍然需要足够的内存来包含解析器创建的所有对象:
GsonBuilder gb = new GsonBuilder(); // configure this as necessary
Gson gson = gb.create();
final Result response = gson.fromJson(
new InputStreamReader(is, Charset.forName("UTF-8")),
Result.class
);
"结果"这是一个包含JSON响应数据的类。您必须确保所有映射都适用于您的数据,因此请阅读GSON并根据您的情况执行任何操作。
如果将JSON数据存储在资产中,也可以使用它来解析JSON数据。只需将资产数据的InputStream交给它,它的工作方式也一样。
答案 3 :(得分:0)
您可以按照建议将JSON嵌入到应用程序的代码中,但如果JSON是动态的,这将是一个糟糕的方法。然后,只要JSON发生变化,您就需要为应用程序推送更新。
更好的解决方案是对从WebService生成的JSON进行分页,即将JSON分解为可以在单独的API调用中按顺序获取的较小部分。
答案 4 :(得分:0)
最好尝试将Json对象分解为较小的对象并从webService获取
或获取部分数据,如果你不能这样做
您必须使用流式JSON解析器。 对于Android,你可以使用这两个:
GSON
杰克逊
GSON Streaming在https://sites.google.com/site/gson/streaming
解释我个人喜欢Gson。
答案 5 :(得分:0)
以下课程ApiUrlClass.java
包含您需要的所有方法。请阅读我写的课程评论。这将帮助您做您需要的事情。这也使用透明。
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.StringBody;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.UnknownHostException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;
/*
Usage of the class
Create all the necessary API Call methods you need.
And either use a Thread or AsyncTask to call the following.
JSONObject response = ApiUrlCalls.login("username", "passowrd");
After the response is obtained, check for status code like
if(response.getInt("status_code") == 200){
//TODO: code something
} else {
//TODO: code something
}
*/
public class ApiUrlCalls {
private String HOST = "https://domain/path/"; //This will be concated with the function needed. Ref:1
/*
Now utilizing the method is so simple. Lets consider a login function, which sends username and password.
See below for example.
*/
public static JSONObject login(String username, String password){
String functionCall = "login";
Uri.Builder builder = new Uri.Builder()
.appendQueryParameter("username", username)
.appendQueryParameter("password", password);
/*
The return calls the apiPost method for processing.
Make sure this should't happen in the UI thread, orelse, NetworkOnMainThread exception will be thrown.
*/
return apiPost(builder, functionCall);
}
/*
This method is the one which performs POST operation. If you need GET, just change it
in like Connection.setRequestMethod("GET")
*/
private static JSONObject apiPost(Uri.Builder builder, String function){
try {
int TIMEOUT = 15000;
JSONObject jsonObject = new JSONObject();
try {
URL url = null;
String response = "";
/*
Ref:1
As mentioned, here below, in case the function is "login",
url looks like https://domain/path/login
This is generally a rewrited form by .htaccess in server.
If you need knowledge on RESTful API in PHP, refer
http://stackoverflow.com/questions/34997738/creating-restful-api-what-kind-of-headers-should-be-put-out-before-the-response/35000332#35000332
I have answered how to create a RESTful API. It matches the above URL format, it also includes the .htaccess
*/
url = new URL(HOST + function);
HttpsURLConnection conn = null;
conn = (HttpsURLConnection) url.openConnection();
assert conn != null;
conn.setReadTimeout(TIMEOUT);
conn.setConnectTimeout(TIMEOUT);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
String query = builder.build().getEncodedQuery();
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
writer.write(query);
writer.flush();
writer.close();
os.close();
conn.connect();
int responseCode = conn.getResponseCode();
String responseMessage = conn.getResponseMessage();
jsonObject.put("status_code", responseCode);
jsonObject.put("status_message", responseMessage);
/*The if condition below will check if status code is greater than 400 and sets error status
even before trying to read content, because HttpUrlConnection classes will throw exceptions
for status codes 4xx and 5xx. You cannot read content for status codes 4xx and 5xx in HttpUrlConnection
classes.
*/
if (jsonObject.getInt("status_code") >= 400) {
jsonObject.put("status", "Error");
jsonObject.put("msg", "Something is not good. Try again later.");
return jsonObject;
}
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = br.readLine()) != null) {
response += line;
}
//Log.d("RESP", response);
/*
After the actual payload is read as a string, it is time to change it into JSON.
Simply when it starts with "[" it should be a JSON array and when it starts with "{"
it is a JSONObject. That is what hapenning below.
*/
if(response.startsWith("[")) {
jsonObject.put("content", new JSONArray(response));
}
if(response.startsWith("{")){
jsonObject.put("content", new JSONObject(response));
}
} catch(UnknownHostException e) {
//No explanation needed :)
jsonObject.put("status", "UnknownHostException");
jsonObject.put("msg", "Check your internet connection");
} catch (SocketTimeoutException){
//This is when the connection timeouts. Timeouts can be modified by TIMEOUT variable above.
jsonObject.put("status", "Timeout");
jsonObject.put("msg", "Check your internet connection");
} catch (SSLPeerUnverifiedException se) {
//When an untrusted SSL Certificate is received, this happens. (Only for https.)
jsonObject.put("status", "SSLException");
jsonObject.put("msg", "Unable to establish secure connection.");
se.printStackTrace();
} catch (IOException e) {
//This generally happens when there is a trouble in connection
jsonObject.put("status", "IOException");
jsonObject.put("msg", "Check your internet connection");
e.printStackTrace();
} catch(FileNotFoundException e){
//There is no chance that this catch block will execute as we already checked for 4xx errors
jsonObject.put("status", "FileNotFoundException");
jsonObject.put("msg", "Some 4xx Error");
e.printStackTrace();
} catch (JSONException e){
//This happens when there is a troble reading the content, or some notice or warnings in content,
//which generally happens while we modify the server side files. Read the "msg", and it is clear now :)
jsonObject.put("status", "JSONException");
jsonObject.put("msg", "We are experiencing a glitch, try back in sometime.");
e.printStackTrace();
} return jsonObject;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}