Android ProgressBar停止更新
我正在尝试解决我的应用程序的UI问题 当进入特定的Android ProgressBar停止更新,android,multithreading,android-asynctask,android-ui,Android,Multithreading,Android Asynctask,Android Ui,我正在尝试解决我的应用程序的UI问题 当进入特定的活动时,应用程序会在目录中查找一些文件,并为每个文件向REST API服务请求一些数据 工作线程实现为一个异步任务: doInBackground方法递归搜索文件夹及其子文件夹中的文件。 如果找到一个文件,一个新的请求将被提交到一个请求队列,该队列由Reformation+OkHTTPClient处理 请求是异步的,Callback函数在检索到文件信息后,会调用执行某些操作的函数,然后调用AsyncTaskpublishProgress() 最后
活动时
,应用程序会在目录中查找一些文件,并为每个文件向REST API服务请求一些数据
工作线程实现为一个异步任务
:
doInBackground
方法递归搜索文件夹及其子文件夹中的文件。
如果找到一个文件,一个新的请求将被提交到一个请求队列,该队列由Reformation+OkHTTPClient处理
请求是异步的,Callback
函数在检索到文件信息后,会调用执行某些操作的函数,然后调用AsyncTask
publishProgress()
最后调用onProgressUpdate
来更新ProgressBar
的当前值和最大值
我遇到的主要问题是,经过一段时间后,ProgressBar
停止更新,我收到“Choreographer dropped frames”消息,但每次调用onProgressUpdate
时都会使用更新的值
我认为许多HTTP请求是频繁UI更新的瓶颈
我还尝试创建一个优先级设置为MAX\u priority
的线程,从中调用publishProgress
,没有区别
我应该遵循哪种模式来提高UI的响应性
下面是一些简化的代码:
异步任务
public class MyAsyncTask implements myCustomListener{
private int processed = 0;
private int toProcess = 0;
private MyCustomActivity mActivity;
public MyAsyncTask(MyCustomActivity mActivity){
this.mActivity = mActivity;
}
@Override
protected Void doInBackground(Void... arg0) {
doScan(mRootDir);
return null;
}
private void doScan(File rootDir){
for(File file: rootDir.listFiles()){
if(file.isDirectory()) doScan(file);
else if(isWantedFile(file)) {
MyQueues.addRequest(file,this);
toProcess++;
}
}
}
@Override
public void onCustomEventListened(File f){
//set f as processed
processed++;
publishProgress();
}
@Override
protected void onProgressUpdate(Void... voids) {
if (processed > 1)
mActivity.showProgressBar(); //If not visible, set visible
mActivity.updateProgressBar(processed, toProcess);
Log.i("Scan Progress", processed + "/" + toProcess); //this log print tells me that method is called properly
if (processed == toProcess) {
mActivity.hideProgressBar(); //If visible, set not visible
}
}
}
public class MyCallback implements Callback<FileInfoClass>{
private File f;
private MyCustomListener mListener;
public MyCallback(File f, MyCustomListener mListener){
this.f=f;
this.mListener=mListener;
}
@Override
public void failure(RetrofitError response) {
mListener.onCustomEventListened(f);
}
@Override
public void success(FileInfoClass fic, Response response) {
if(check(fic,f)){
//store fic data...
}
mListener.onCustomEventListened(f);
}
}
请求队列
public class MyQueues{
private static LinkedBlockingQueue<Runnable> mRequestQueue = new LinkedBlockingQueue<Runnable>();
private static ThreadPoolExecutor tpe = new ThreadPoolExecutor(4, 4, Long.MAX_VALUE, TimeUnit.NANOSECONDS, mRequestQueue);
private static OkClient mOkClient;
private static OkHttpClient mOkHttpClient;
static{
if(null==mOkHttpClient){
File cache = MyApp.getCacheDir();
HttpResponseCache resCache;
try {
resCache = new HttpResponseCache(cache, 10L * 1024 * 1024);
mOkHttpClient = new OkHttpClient();
mOkHttpClient.setResponseCache(resCache);
} catch (IOException e) {
}
}
if(null==mOkClient){
mOkClient = new OkClient(mOkHttpClient);
}
}
public static interface TheGamesDBService {
@GET("/getData.php")
void getData(@Query("id") String id, MyCallback<FileInfoClass> cb);
}
private static RestAdapter myAdapter = new RestAdapter.Builder()
.setClient(mOkClient).setConverter(myConverter())
.setExecutors(tpe, new MainThreadExecutor())
.setEndpoint(Constants.MYENDPOINT).build();
private static MyService mService = myAdapter
.create(MyService.class);
public static void addRequest(File f, MyCustomListener mListener) {
MyCallback cb = new MyCallback(f, mListener);
myService().getData(f.getName(),cb);
}
}
}
公共类MyQueues{
私有静态LinkedBlockingQueue mRequestQueue=新LinkedBlockingQueue();
私有静态ThreadPoolExecutor tpe=新的ThreadPoolExecutor(4,4,Long.MAX_值,TimeUnit.NANOSECONDS,mRequestQueue);
私有静态OkClient-mOkClient;
私有静态Okhttp客户端mokhttp客户端;
静止的{
if(null==mOkHttpClient){
文件缓存=MyApp.getCacheDir();
HttpResponseCache-resCache;
试一试{
resCache=新的HttpResponseCache(缓存,10L*1024*1024);
mOkHttpClient=new-OkHttpClient();
mOkHttpClient.setResponseCache(resCache);
}捕获(IOE异常){
}
}
if(null==mOkClient){
mOkClient=新的OkClient(mOkHttpClient);
}
}
公共静态界面游戏服务{
@获取(“/getData.php”)
void getData(@Query(“id”)字符串id,MyCallback cb);
}
private static RestAdapter myAdapter=new RestAdapter.Builder()
.setClient(mOkClient).setConverter(myConverter())
.setExecutors(tpe,新的MainThreadExecutor())
.setEndpoint(Constants.MYENDPOINT).build();
私有静态MyService mService=myAdapter
.create(MyService.class);
公共静态void addRequest(文件f,MyCustomListener mListener){
MyCallback cb=新的MyCallback(f,mListener);
myService().getData(f.getName(),cb);
}
}
}
MyCallback
public class MyAsyncTask implements myCustomListener{
private int processed = 0;
private int toProcess = 0;
private MyCustomActivity mActivity;
public MyAsyncTask(MyCustomActivity mActivity){
this.mActivity = mActivity;
}
@Override
protected Void doInBackground(Void... arg0) {
doScan(mRootDir);
return null;
}
private void doScan(File rootDir){
for(File file: rootDir.listFiles()){
if(file.isDirectory()) doScan(file);
else if(isWantedFile(file)) {
MyQueues.addRequest(file,this);
toProcess++;
}
}
}
@Override
public void onCustomEventListened(File f){
//set f as processed
processed++;
publishProgress();
}
@Override
protected void onProgressUpdate(Void... voids) {
if (processed > 1)
mActivity.showProgressBar(); //If not visible, set visible
mActivity.updateProgressBar(processed, toProcess);
Log.i("Scan Progress", processed + "/" + toProcess); //this log print tells me that method is called properly
if (processed == toProcess) {
mActivity.hideProgressBar(); //If visible, set not visible
}
}
}
public class MyCallback implements Callback<FileInfoClass>{
private File f;
private MyCustomListener mListener;
public MyCallback(File f, MyCustomListener mListener){
this.f=f;
this.mListener=mListener;
}
@Override
public void failure(RetrofitError response) {
mListener.onCustomEventListened(f);
}
@Override
public void success(FileInfoClass fic, Response response) {
if(check(fic,f)){
//store fic data...
}
mListener.onCustomEventListened(f);
}
}
公共类MyCallback实现回调{
私有文件f;
私人MyCustomListener;
公共MyCallback(文件f,MyCustomListener mListener){
这个。f=f;
this.mListener=mListener;
}
@凌驾
公共无效故障(错误响应){
mListener.onCustomEventListened(f);
}
@凌驾
public void成功(FileInfoClass,响应){
如果(检查(fic,f)){
//存储fic数据。。。
}
mListener.onCustomEventListened(f);
}
}
单看这段代码很难对其进行调查,但我看到了潜在的问题
改装回调方法:failure()
和success()
在主线程上被调用,最终publishProgress()在主线程上调用代码>。根据AsyncTask文档,这个方法应该从在专用后台线程上调用的doInBackground()
方法调用。您应该明确地考虑重构代码。为了更方便地在不同位置打印日志以记录当前线程名称:thread.currentThread().getName()
此外,我注意到您在AsyncTask
中保留了对Activity
的强引用。这是一种非常糟糕的做法。要轻松修复它,请使用WeakReference
类包装Activity
引用
如果您决定进行更大的更改,我建议您使用ThreadExecutor将后台操作移动到专用的服务
,或者使用IntentService
,它提供现成的排队后台操作。最后,要将进度更改传达给活动
,请使用BroadcastReceiver
以及LocalBroadcastManager
更新
还有一件事要补充。如果您自己在后台处理网络操作,则无需使用改装的回调。这对于直接从UI执行请求很好。相反,同步调用改装请求 你能发布你的代码吗?不幸的是,我不能发布整个代码,因为它很长。如果你告诉我你想看什么部分,我可以发布其中的一些部分。我想看看你在哪里执行改装调用、改装回调、AsyncTask onProgressUpdate以及在哪里使用你的ProgressBar。@Loop抱歉,如果花了这么长时间,我添加了你要求的简化代码。谢谢你宝贵的提示!我按照您的指示编辑了我的代码:我删除了回调
s以在后台执行整个代码,现在ProgressBar
已正确更新~6000个请求,但仍然没有滞后的用户界面!