Android:我的异步任务是 运行 在 ui 线程上并停止了我的应用程序
Android: My async task is running on the ui thread and stalling my app
在我的应用程序中,我有两个异步任务,这两个任务都会进行 API 次调用。
首先,asynctask1 命中一个 url 端点,然后我解析出我的下一个(更强大的)asynctask 需要命中的每个类别的页面数。例如:我的第一个异步任务会给我一个看起来像
的数组
int[] arr = {1,5,12,40,1,0,40...,6}
所以基本上,这意味着将有 {以上数组的总和} 个不同的端点供我点击以获取我的数据。
然后这个数组传到我的 asynctask2。 Asynctask2 有两个 for 循环。外部 forloop 用于每个类别(有 26 个类别,每个字母对应 1 个类别)。内部 for 循环根据上面的数组为该类别列出的页面数量遍历该类别的每个页面。
我在 asynctask2 中进行了大约 300 API 次调用。出于某种原因,这似乎使我的 UI 线程陷入困境,即使它应该在后台 运行。
下面是我的 asynctask2 代码(警告:随之而来的丑陋代码)
public class ItemDatabaseUpdater extends AsyncTask<ArrayList<Integer>, Void, ArrayList<Item>> {
private String apiRoute = "http://services.runescape.com/m=itemdb_oldschool/api/catalogue/items.json?category=1&alpha=";
private String apiLetter = "b";
private String apiRoutePage = "&page=";
private String apiPageNumber = "1";
private String data;
private ArrayList<Item> itemDB = new ArrayList<>();
private JSONParser jsonParser = new JSONParser();
private JSONArray jsonArray;
private String[] alphabet = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
private Item _item;
protected void onPreExecute() {}
protected ArrayList<Item> doInBackground(ArrayList<Integer>... args) {
ArrayList<Integer> pageNumbersForEachLetter = getTotalPageCountForEachLetter(args[0]);
for (int i=0; i<pageNumbersForEachLetter.size(); i++){
apiLetter = alphabet[i];
for (int j=1; j<pageNumbersForEachLetter.get((i))+1; j++){
apiPageNumber = String.valueOf(j);
try {
String endRoute = apiRoute + apiLetter + apiRoutePage + apiPageNumber;
URL url = new URL(endRoute);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String dataEntry;
while ((dataEntry = br.readLine()) != null) {
stringBuilder.append(dataEntry).append("\n");
}
br.close();
data = stringBuilder.toString();
jsonArray = jsonParser.extractArrayFromObject(data, "items");
for(int k=0; k<jsonArray.length(); k++) {
JSONObject obj = jsonParser.extractObjectFromArray(jsonArray, k);
JSONObject currentDataObj = jsonParser.extractObjectFromObject(obj, "current");
JSONObject todayDataObj = jsonParser.extractObjectFromObject(obj, "today");
_item = new Item();
_item.setIconUrl(jsonParser.extractValueFromObject(obj,"icon"));
_item.setId(jsonParser.extractValueFromObject(obj,"id"));
_item.setName(jsonParser.extractValueFromObject(obj,"name"));
_item.setCurrentPrice(jsonParser.extractValueFromObject(currentDataObj,"price"));
_item.setPriceChangeToday(jsonParser.extractValueFromObject(todayDataObj,"price"));
_item.setTrendToday(jsonParser.extractValueFromObject(todayDataObj,"trend"));
itemDB.add(_item);
}
}
finally{
urlConnection.disconnect();
}
}
catch (Exception e){return null;}
}
}
return itemDB;
}
protected void onPostExecute(ArrayList<String> response) {}
private ArrayList<Integer> getTotalPageCountForEachLetter(ArrayList<Integer> arg){
ArrayList<Integer> retArr = new ArrayList<>();
for (int i : arg){
retArr.add((int)(Math.ceil(i/12)));
}
return retArr;
}
}
根据请求,这里是我如何调用我的 asynctask2
try {itemDatabase = itemDatabaseUpdater.execute(itemCatagoryNumbers).get();} catch (Exception e){}
您正在 AsyncTask
上呼叫 get()
。这表示 "tie up the current thread until the task completes"。由于您当前的线程是主应用程序线程,您正在阻塞该线程,这完全消除了首先使用 AsyncTask
的价值。
移除您的 get()
通话。在 onPostExecute()
中使用您的任务结果,它在主应用程序线程上调用,因此您可以安全地在那里更新您的 UI。
在我的应用程序中,我有两个异步任务,这两个任务都会进行 API 次调用。
首先,asynctask1 命中一个 url 端点,然后我解析出我的下一个(更强大的)asynctask 需要命中的每个类别的页面数。例如:我的第一个异步任务会给我一个看起来像
的数组int[] arr = {1,5,12,40,1,0,40...,6}
所以基本上,这意味着将有 {以上数组的总和} 个不同的端点供我点击以获取我的数据。
然后这个数组传到我的 asynctask2。 Asynctask2 有两个 for 循环。外部 forloop 用于每个类别(有 26 个类别,每个字母对应 1 个类别)。内部 for 循环根据上面的数组为该类别列出的页面数量遍历该类别的每个页面。
我在 asynctask2 中进行了大约 300 API 次调用。出于某种原因,这似乎使我的 UI 线程陷入困境,即使它应该在后台 运行。
下面是我的 asynctask2 代码(警告:随之而来的丑陋代码)
public class ItemDatabaseUpdater extends AsyncTask<ArrayList<Integer>, Void, ArrayList<Item>> {
private String apiRoute = "http://services.runescape.com/m=itemdb_oldschool/api/catalogue/items.json?category=1&alpha=";
private String apiLetter = "b";
private String apiRoutePage = "&page=";
private String apiPageNumber = "1";
private String data;
private ArrayList<Item> itemDB = new ArrayList<>();
private JSONParser jsonParser = new JSONParser();
private JSONArray jsonArray;
private String[] alphabet = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
private Item _item;
protected void onPreExecute() {}
protected ArrayList<Item> doInBackground(ArrayList<Integer>... args) {
ArrayList<Integer> pageNumbersForEachLetter = getTotalPageCountForEachLetter(args[0]);
for (int i=0; i<pageNumbersForEachLetter.size(); i++){
apiLetter = alphabet[i];
for (int j=1; j<pageNumbersForEachLetter.get((i))+1; j++){
apiPageNumber = String.valueOf(j);
try {
String endRoute = apiRoute + apiLetter + apiRoutePage + apiPageNumber;
URL url = new URL(endRoute);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String dataEntry;
while ((dataEntry = br.readLine()) != null) {
stringBuilder.append(dataEntry).append("\n");
}
br.close();
data = stringBuilder.toString();
jsonArray = jsonParser.extractArrayFromObject(data, "items");
for(int k=0; k<jsonArray.length(); k++) {
JSONObject obj = jsonParser.extractObjectFromArray(jsonArray, k);
JSONObject currentDataObj = jsonParser.extractObjectFromObject(obj, "current");
JSONObject todayDataObj = jsonParser.extractObjectFromObject(obj, "today");
_item = new Item();
_item.setIconUrl(jsonParser.extractValueFromObject(obj,"icon"));
_item.setId(jsonParser.extractValueFromObject(obj,"id"));
_item.setName(jsonParser.extractValueFromObject(obj,"name"));
_item.setCurrentPrice(jsonParser.extractValueFromObject(currentDataObj,"price"));
_item.setPriceChangeToday(jsonParser.extractValueFromObject(todayDataObj,"price"));
_item.setTrendToday(jsonParser.extractValueFromObject(todayDataObj,"trend"));
itemDB.add(_item);
}
}
finally{
urlConnection.disconnect();
}
}
catch (Exception e){return null;}
}
}
return itemDB;
}
protected void onPostExecute(ArrayList<String> response) {}
private ArrayList<Integer> getTotalPageCountForEachLetter(ArrayList<Integer> arg){
ArrayList<Integer> retArr = new ArrayList<>();
for (int i : arg){
retArr.add((int)(Math.ceil(i/12)));
}
return retArr;
}
}
根据请求,这里是我如何调用我的 asynctask2
try {itemDatabase = itemDatabaseUpdater.execute(itemCatagoryNumbers).get();} catch (Exception e){}
您正在 AsyncTask
上呼叫 get()
。这表示 "tie up the current thread until the task completes"。由于您当前的线程是主应用程序线程,您正在阻塞该线程,这完全消除了首先使用 AsyncTask
的价值。
移除您的 get()
通话。在 onPostExecute()
中使用您的任务结果,它在主应用程序线程上调用,因此您可以安全地在那里更新您的 UI。