我很困惑何时会在Handler上选择AsyncTask。假设我有一些代码,我想每n秒运行一次,这将更新UI。为什么我会选择一个而不是另一个?
答案 0 :(得分:73)
IMO,AsyncTask的编写是为了提供一种方便,易用的方式来实现Android应用程序中的后台处理,而不必过多担心低级细节(线程,消息循环等)。它提供了回调方法,可以帮助您安排任务,并在需要时轻松更新UI。
但是,重要的是要注意,在使用AsyncTask时,开发人员正在提交其限制,这是因为该类作者所做的设计决策。对于例如我最近发现使用AsyncTasks可以安排的作业数量有限制。
Handler对两者更加透明,可能会给你更多自由;所以,如果你想要更多控制你会选择Handler,否则AsynTask会正常工作。
答案 1 :(得分:60)
我的经验法则是:
如果您正在做与UI相关的隔离事宜,例如下载数据以显示在列表中,请继续使用AsyncTask
。
如果您正在执行多个重复任务,例如下载要在下载时显示在ImageViews
中的多个图像(如下载缩略图),请使用Handler
的任务队列。< / p>
答案 2 :(得分:18)
尽可能避免使用AsyncTask主要是出于以下原因:
AsyncTask不能保证运行,因为系统设置了ThreadPool基数和最大大小,如果你创建了太多的asynctask,它们最终会被销毁
AsyncTask即使在运行时也可以自动终止,具体取决于活动生命周期而且您无法控制它
在UI线程上运行的AsyncTask方法,如onPostExecute,可以在它所引用的Activity,不再可见,或者可能处于不同的布局状态时执行,就像在方向更改后一样。
总之,你不应该使用AsyncTask的UIThread链接方法,这是它的主要优势!此外,您应该只对doInBackground进行非关键性工作。 阅读此主题以获得有关此问题的更多见解:
Is AsyncTask really conceptually flawed or am I just missing something?
结束尝试更倾向于使用IntentServices,HandlerThread或ThreadPoolExecutor而不是AsyncTask,而上述任何一个问题都可能引起您的关注。当然它需要更多的工作,但你的应用程序会更安全。
答案 3 :(得分:15)
如果您想每x秒进行一次计算,您应该在Runnable
(Handler
)上安排postDelayed()
,Runnable
应该从当前的UI线程。如果要在另一个线程中启动它,请使用HandlerThread。
AsyncTask对我们来说更容易使用,但并不比处理程序更好。
答案 4 :(得分:6)
Handler与应用程序的主线程相关联。它处理和调度从后台线程发送到app主线程的消息和runnable。
AsyncTask提供了一种处理后台线程的简单方法,以便通过耗时的操作来更新UI而不会阻塞它。
答案是两者都可用于从后台线程更新UI,区别在于您的执行场景。您可以考虑使用处理程序来发布延迟消息或按特定顺序将消息发送到MessageQueue。
如果你想以一种简单方便的方式在app主线程和后台线程之间交换参数(从而更新UI),你可以考虑使用AsyncTask。
答案 5 :(得分:1)
public class WifiItemListAdapter extends BaseAdapter {
protected List<ScanResult> scanResults;
public LayoutInflater inflater;
public WifiItemListAdapter(Context context, List<ScanResult> scanResult){
super();
this.scanResults = scanResult;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public int getCount() {
return scanResults.size();
}
@Override
public Object getItem(int i) {
return scanResults.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.item_wifi, null);
holder.imageView = (ImageView) convertView.findViewById(R.id.wifi_icon);
holder.tvPrimary = (TextView) convertView.findViewById(R.id.device_id);
holder.tvSecondary = (TextView) convertView.findViewById(R.id.wifi_power);
holder.imageView.setImageResource(R.drawable.ic_wifi_black_24dp);
holder.tvPrimary.setText(scanResults.get(position).SSID);
holder.tvSecondary.setText("RSSI: " + scanResults.get(position).level + " dBm");
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
holder.tvPrimary.setText(scanResults.get(position).SSID);
holder.tvSecondary.setText("Power: " + scanResults.get(position).level + " dBm");
}
return convertView;
}
public static class ViewHolder{
ImageView imageView;
TextView tvPrimary;
TextView tvSecondary;
}
}
假设在完成一些后台工作后,您将在UI线程上执行某些操作。此外,您只能执行一次(此后,其状态为AsyncTask
,您将再次尝试执行该异常)。而且,使用它的灵活性并不多。是的,您可以使用FINISHED
进行并行执行,但这种努力可能不值得。
THREAD_POOL_EXECUTOR
不会设定任何内容。此外,可以根据需要运行多次。您可以自由决定必须连接哪个线程,如何与其他处理程序通信,也可以使用Handler
生成它们。因此,它更灵活,适合重复工作。
检查不同类型的HandlerThread
示例here。
答案 6 :(得分:0)
他们是最好的面试问题。 AsyncTask - 它们用于卸载UI线程并在后台执行任务。 处理程序 - Android dosent在UI和后台线程之间有直接的通信方式。必须使用处理程序通过消息队列发送消息或runnable。
所以AsyncTasks用于需要在后台执行任务的地方,Handler用于UI和后台线程之间的通信。
答案 7 :(得分:0)
doInBackground - 基本上可以在另一个线程中工作。 onPostExecute - 在UI线程上发布结果,它在内部向主线程的处理程序发送消息。主UI线程已经有一个looper和与之关联的处理程序。
所以基本上,如果你必须做一些后台任务,请使用AsyncTask。但最终,如果需要在UI上更新某些内容,它将使用主线程的处理程序。
答案 8 :(得分:0)
AsyncTask =线程+处理程序
处理程序-它是一种允许处理消息队列的机制。它绑定到具有Looper的具体线程。
请在此处阅读更多信息-https://blog.mindorks.com/android-core-looper-handler-and-handlerthread-bd54d69fe91a