问题
The app i'm developing downloads a JSON file from remote address at every startup and then it parses the JSON Object and copies data to SQLite on the phone. This operation is the cause for which the app hangs for some seconds on every startup showing blank screen (or sometime blank and then black screen), in fact if i tried to disable this part of code the app starts quickly, with no hang. So, how could i do it better?
Here is the code (DataHandler class) related to file download, parsing and writing to local SQLite db:
public class DataHandler {
public DataHandler() {
}
public int storeData(Database db, int num) throws JSONException {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("http://www.example.com/data.json");
request.addHeader("Cache-Control", "no-cache");
long id = -1;
try {
HttpResponse response = client.execute(request);
HttpEntity entity = response.getEntity();
InputStreamReader in = new InputStreamReader(entity.getContent());
BufferedReader reader = new BufferedReader(in);
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while ((line=reader.readLine()) != null) {
stringBuilder.append(line);
}
JSONArray jsonArray = new JSONArray(stringBuilder.toString());
SQLiteDatabase dbWrite = db.getWritableDatabase();
ContentValues values = new ContentValues();
if (jsonArray.length() == num && num != 0)
return num;
SQLiteDatabase dbread = db.getReadableDatabase();
dbread.delete("mytable", "1", null);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jObj = (JSONObject) jsonArray.getJSONObject(i);
values.put("_id", jObj.optString("id").toString());
values.put("city", jObj.optString("city").toString());
values.put("country",jObj.optString("country").toString());
values.put("addr", jObj.optString("addr").toString());
values.put("title", jObj.optString("title").toString());
values.put("lon", jObj.optString("lon").toString());
values.put("email", jObj.optString("email").toString());
values.put("phone", jObj.optString("phone").toString());
values.put("web", jObj.optString("web").toString());
values.put("lat", jObj.optString("lat").toString());
values.put("desc", jObj.optString("desc").toString());
values.put("icon", jObj.optString("icon").toString());
values.put("category", jObj.optString("category").toString());
id = dbWrite.insert("merchants", null, values);
}
num = jsonArray.length();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (id > 0)
return num;
else
return -1;
}
}
回答1:
You should probably to the download and parsing in the background and display some kind of splashscreen with progress information in the meantime. To avoid an annoying splash screen, you could also cache the data and display your app normally on startup, and only refresh the data once the bakground update is finished.
There are several options to do the download and parse operations in the background :
- use an AsyncTask
- use a service
I cannot say what's the best solution in your specific case, but I would recommend reading the Processes and Threads and service documentation.
回答2:
Her goes your Async Task Class
class AsyncClass extends AsyncTask<String,Void,String>
{
int result;
Context context;
ProgressDialog bar;
AsynclassListener<String> listener;
public AsyncClass(Context context, AsynclassListener listener) {//add more parameter as your method body has (i.e Database db, int num) . Don't forget to initialize them.
this.context=context;
this.listener=listener;
bar = new ProgressDialog(context);
bar.setIndeterminate(false);
//make your progressBar here I have just given a simple example for above PB there are more parameters to set.
}
protected String doInBackground(String... Param){
try{
result = storeData();//call your method here
}catch(Exception e){
// Do something when crash
}
return ""+result;
}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
bar.show();// By the time your data fetching and parsing will go on you this progress bar will be visible.
}
@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
bar.dismiss();//As soon as the work is complete the this method is called.
listener.onTaskComplete(""+result);
/**
* In your case you can later typecast back in integer once you recieve the result.
* this listener will post the result to your main activity.
*/
}
}
Here is your Interface
public interface AsynclassListener<T>{
public void onTaskComplete(T result);
}
Now Let your Activity (Splash Class) implement the interface This will implement the method as :
@Override
public void onTaskComplete(String result) {
// here the asynclass will post the result as 1 or -1 whatever you want.
//After that you may proceed with your next part i.e switching to next activity or so.
}
Edit: I forgot to mention about how this will be called :
new AsyncClass(getApplicationContext(), this).execute("");// here you have to enter the database and other parameter values that will be required to run the method. Change it accordingly.
As you can see here in your method you are fetching the data from net and parsing also : There is again a second approach in which you can call the network cal in a separate thread and later the parsing can be done further on UIthread.
Also read about the Async Task Class so as to know about the arguments and the working of class.
来源:https://stackoverflow.com/questions/24991513/blank-black-screen-on-app-startup-due-data-downloading