我有一个活动,其中包含2个片段,每个片段有2个list views
,每个片段都有一个适配器。
因此,我从服务器json
获取相当长的数据,我使用AsyncTask
,在post execute
上,我解析数据。问题是它将加载动画冻结4-5秒。
我曾尝试使用Handler
线程,但问题仍然存在,我必须在这里做一些非常错误的事情。
public class DataService extends AsyncTask<String, String, Void> {
@Override
protected Void doInBackground(String... params) {
url = new URL(DATA_URL);
//Connection stuff
String jsonString = stringBuilder.toString();
jsonObject = new JSONObject(jsonString);
//Adding data in Java Objects
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
//Upcoming List in Fragment
allDataFragment.setUpcomingDataList(UpcomingAllDataList);
awayFragment.setUpcomingDataList(tUpcomingAwayList);
homeFragment.setUpcomingDataList(tUpcomingHomeList);
//Past List in Fragment
allDataFragment.setPastDataList(pastAllDataList);
awayFragment.setPastDataList(pastAwayList);
homeFragment.setPastDataList(pastHomeList);
}
我在适配器中添加了日志消息,我可以看到在解析行时它会冻结,所以它需要处理程序线程中的所有后期执行内容
Handler handler= new Handler();
handler.post(new Runnable() {
@Override
public void run() {
//Upcoming List in Fragment
allDataFragment.setUpcomingDataList(UpcomingAllDataList);
awayFragment.setUpcomingDataList(tUpcomingAwayList);
homeFragment.setUpcomingDataList(tUpcomingHomeList);
//Past List in Fragment
allDataFragment.setPastDataList(pastAllDataList);
awayFragment.setPastDataList(pastAwayList);
homeFragment.setPastDataList(pastHomeList);
}
});
我还尝试在Adapter
中添加处理程序,但无法从那里加载UI
组件。
这是我的片段代码的片段。
if (pastListView != null) {
PastListAdapter allGamesAdapter = new PastListAdapter(getContext(), pastAllDataList);
pastListView.setAdapter(allGamesAdapter);
}
在适配器中我正在做以下事情。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView vScore = (TextView) v.findViewById(R.id.v_score);
TextView date = (TextView) v.findViewById(R.id.date);
ImageView image = (ImageView) v.findViewById(R.id.iv_image);
//7 Other views
vScore.setText(dataList.get(position).getScore);
date.setText(dataList.get(position).date);
Log.d(TAG, "getView: Row");
return v;
}
加载动画在开始时工作正常,但是当它开始解析适配器中的数据时,它会挂起UI线程。
答案 0 :(得分:3)
使用GridView gv;
Context context;
ArrayList prgmName;
public static String [] categorylist ={"Cleaner","Mechanic","Plumber","Carpenter"};
public static int [] prgmImages={R.drawable.cleaning,R.drawable.mechanic,R.drawable.plumber,R.drawable.carpenter};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_category);
gv=(GridView) findViewById(R.id.gridView1);
gv.setAdapter(new Adapter_Category_list(this, categorylist,prgmImages));
处理持续时间小于5毫秒(5毫秒)的工作项。由于您从服务器获取了相当长的JSON数据,因此您必须查看其他替代方案(h.each do |k, v|
h[k] = v.first.sort_by { |_, person| person[:age] }.to_h
end
,AsyncTask
和Thread
)
即使您创建HandlerThread
,它也仅在UI线程上运行。而不是ThreadPoolExecutor
,请使用Handler
建议的解决方案:
使用Handler
从服务器获取JSON数据。不阻止UI线程获取数据。
从UI线程的HandlerThread
到HandlerThread
发布数据。 UI处理程序将负责使用HandlerThread
有用的帖子:
Asynctask vs Thread vs Services vs Loader
Handler vs AsyncTask vs Thread
Why to use Handlers while runOnUiThread does the same?(此帖子包含上述解决方案的代码示例)
答案 1 :(得分:2)
使用Volley而不是AsyncTask
答案 2 :(得分:1)
如果它阻止了ui线程,那么就不要在ui线程中执行它
你已经有了一个asyncTask,所以只需使用它并从那里调用你的解析json函数
然后您可以从该任务返回void并从那里更新您的采用者
换句话说,将您的逻辑从onPostExecute转移到doInBackground
答案 3 :(得分:1)
一开始,我建议你,不要懒惰,并期待图书馆
Retrofit - RESTfull client library
您不需要使用这些库编写AsyncTasks,这将使您的生活更轻松,更轻松。
但是,如果你赢了,那好吧。让我们来谈谈AsyncTask问题和您关注的问题。
AsyncTask在后台计算线程上运行,其结果发布在UI线程上。它们由3种泛型类型定义,称为Params,Progress和Result,以及4个步骤,称为begin,doInBackground,进度更新和带有更新UI的计算结束。 因此,当它执行时,任务将经历4个步骤:
1步。 onPreExecute(),在执行任务后立即在UI线程上调用。此步骤主要用于配置任务,例如显示进度条,进度对话框或UI中的任何其他更改。
2步。 doInBackground(Params ...),在onPreExecute()完成执行后立即在后台线程上调用。此步骤用于执行可能需要很长时间的后台计算。异步任务的参数将传递给此步骤。计算结果必须由此步骤返回,并将传递回最后一步。此步骤还可以使用publishProgress(Progress ...)发布一个或多个进度单元。这些值发布在UI线程的onProgressUpdate(Progress ...)步骤中。
3步。 onProgressUpdate(进度...),在调用publishProgress后调用UI线程(进度... )。执行的时间是不确定的。此方法用于在后台计算仍在执行时显示用户界面中的任何形式的进度。例如,它可用于为进度条设置动画或在文本字段中显示日志。
4步。 onPostExecute(Result),在后台计算完成后在UI线程上调用。后台计算的结果作为参数传递给此步骤。
所以,就像你现在一样,如果你不想要捕捉性能冻结,你必须在两步中返回计算结果。
public class DataService extends AsyncTask<String, String, List<UpcomingAllDataList>> {
@Override
protected List<UpcomingAllDataList> doInBackground(String... params) {
// making HTTP request
return UpcomingAllDataList; // return results of Http request
}
@Override
protected void onPostExecute(List<UpcomingAllDataList> upcomingAllDataList) {
super.onPostExecute(upcomingAllDataList);
//Upcoming List in Fragment
allDataFragment.setUpcomingDataList(upcomingAllDataList);
// all another work
}
}
希望,这将是有用的。
答案 4 :(得分:0)
你应该真正使用Retrofit进行服务器调用+解析 Retrofit Github
我认为真正的问题是您在setUpcomingDataList(和所有其他)方法中解析更多数据。
无论如何,HandlerThread
的实例实际上是在UI线程中发生的,因为Handler
的默认构造函数接受了构造Handler
的当前线程(在你的案例是UI线程)并将Runnable
发布到该线程。
无论如何2 - 看看方法是否真的可以在不同的线程中工作(我想你会得到一个android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
)你可以尝试用普通的线程包装你的代码:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//Upcoming List in Fragment
allDataFragment.setUpcomingDataList(UpcomingAllDataList);
awayFragment.setUpcomingDataList(tUpcomingAwayList);
homeFragment.setUpcomingDataList(tUpcomingHomeList);
//Past List in Fragment
allDataFragment.setPastDataList(pastAllDataList);
awayFragment.setPastDataList(pastAwayList);
homeFragment.setPastDataList(pastHomeList);
}
});
thread.start();
这是一个非常糟糕的做法 - 正如我之前所说,使用Retrofit。