使用 AsyncTask 会使应用程序变慢

Posted

技术标签:

【中文标题】使用 AsyncTask 会使应用程序变慢【英文标题】:Using AsyncTask makes the app slower 【发布时间】:2014-10-05 16:43:54 【问题描述】:

我有这个problem,你建议使用 AsyncTask 或 Service。 所以现在我第一次使用了一个 AsyncTask 类,我在其中添加了用于下载和解析 JSON 文件的代码。代码如下:

public class HomePage extends Activity
    private Database db = new Database(this);

    protected void onCreate(Bundle savedInstanceState)
        super.onCreate(savedInstanceState);
        setContentView(R.layout.homepage);

        new DownloadDataFromServer().execute(new String[]  "http://www.example.com/data.json" );
    

    protected void onDestroy() 
        super.onDestroy();
        db.close();
    

    // Async Task Class
    private class DownloadDataFromServer extends AsyncTask<String, Integer, String> 
        ProgressDialog dialog;

        @Override
        protected void onCancelled() 
            super.onCancelled();
        

        @Override
        protected void onPreExecute() 
            dialog = new ProgressDialog(HomePage.this);
            dialog.setIndeterminate(false);
            dialog.setMax(100);
            dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            dialog.setCancelable(true);
            dialog.setTitle("Download JSON");
            dialog.setMessage("Please wait..");
            dialog.show();

            super.onPreExecute();
        

        @Override
        protected String doInBackground(String... urls) 
            int count = 0;
            int lenghtOfFile = 0;

            // JSON DOWNLOADING AND PARSING
            SQLiteDatabase dbr = db.getReadableDatabase();

            try 
                StrictMode.ThreadPolicy policy= new StrictMode.ThreadPolicy.Builder().permitAll().build();
                StrictMode.setThreadPolicy(policy);

                HttpClient client = new DefaultHttpClient();
                HttpGet request = new HttpGet(urls[0]);
                request.addHeader("Cache-Control", "no-cache");
                long id = -1;

                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();
                dbr.delete("users", "1", null);

                long total = 0;
                lenghtOfFile = jsonArray.length();

                for (int i = 0; i < lenghtOfFile; i++) 
                    JSONObject jObj = (JSONObject) jsonArray.getJSONObject(i);

                    values.put("_id", jObj.optString("id").toString());
                    values.put("city", jObj.optString("city").toString());
                    values.put("name",jObj.optString("name").toString());

                    id = dbWrite.insert("users", null, values);

                    count++;
                    total += count;
                    onProgressUpdate((int) ((total * 100) / lenghtOfFile));
                           
             catch (ClientProtocolException e) 
                e.printStackTrace();
             catch (IOException e) 
                e.printStackTrace();
             catch (JSONException e) 
                e.printStackTrace();
            

            return lenghtOfFile+"";
        

        protected void onProgressUpdate(Integer... progress) 
            dialog.setProgress(progress[0]);
        

        @Override
        protected void onPostExecute(String result) 
            if (Integer.parseInt(result) < 0) 
                Toast.makeText(getBaseContext(), "Failed!", Toast.LENGTH_SHORT).show();
             else 
                Toast.makeText(getBaseContext(), result + " users", Toast.LENGTH_SHORT).show();
            
            dialog.dismiss();
        
    

达到 100% 需要很长时间,差不多 1 ​​分钟! 除了进度条在 0% 上挂了一会儿,然后它只显示 100%。 可能是什么问题?

【问题讨论】:

你不应该直接打电话给onProgressUpdate()。相反,请致电publishProgress(),这将致电onProgressUpdate() Urrrm,顺便说一句,摆脱你的 StrictMode 东西。我假设它之前在主线程上运行代码时就在那里。 @Squonk 不错! smartmouse,see the docs,关于使用 StrictMode,如果您不知道,请不要将其留在生产版本中。 你说得对,我删除了那 2 行,但它仍然有效。谢谢。 无论如何,主要问题仍然存在:应用程序加载非常缓慢,在等待期间 LogCat 显示:08-12 17:07:46.720: I/Timeline(16921): Timeline: Activity_idle id: android.os.BinderProxy@41b6f398 time:24548374 08-12 17:08:01.525: I/Timeline(16921): Timeline: Activity_idle id: android.os.BinderProxy@41b6f398 time:24563177 【参考方案1】:

这是因为每个 insert() 在 DB 中进行自己的事务。您必须将所有 insert() 调用包装在一个事务中,如下所示:

 dbWrite.beginTransaction();
        try 
           //put all insert() here
            dbWrite.setTransactionSuccessful();

        catch 
            //Error in between database transaction 
        finally 
                dbWrite.endTransaction();

        

祝你好运! :)

另外,您应该使用publishPorgress 方法更新ProgressDialog,而不是直接调用onProgressUpdate

【讨论】:

在使用 AsyncTask 之前,我使用一种方法进行了相同的操作,并且等待时间没有问题。那么为什么使用 AsyncTask,我在其中添加相同的操作,需要这么长时间?实际上,如果我向“id = dbWrite.insert("users", null, values);" 添加注释,则问题不在于每个 insert()我遇到了同样的问题... 我错了,如果我评论 insert() 进度条加载速度很快。所以我在我的代码中应用了你的提示,现在它加载速度很快。非常感谢! 你能解释一下为什么它运作良好吗?在使用 AsyncTask 之前我不需要这个提示,为什么现在我必须使用事务? 一般来说,您已经在每个 insert() 操作上使用了隐式事务。事务对于 db 来说是相当困难的操作(打开、应用、完成)。这样,您只需创建一个事务。实际上,我不知道您为什么在 UI 线程上没有性能问题。你必须有!对于您确实拥有的大数据集。 顺便说一句,有关交易的更多信息,您可以在那里找到:tutorialspoint.com/sql/sql-transactions.htm【参考方案2】:

要更新AsyncTask 的进度,您应该调用publishProgress 方法。 不要直接拨打onPublishProgress

【讨论】:

以上是关于使用 AsyncTask 会使应用程序变慢的主要内容,如果未能解决你的问题,请参考以下文章

html5 应用程序中的 gif 会使应用程序变慢?

将 Oracle 的行大小设置得更高会使我的应用程序变慢?

使用 AsyncTask 解析 HTML 使主线程变慢

一段时间后,AsyncTask 在服务中变慢

为啥使用 DOMDocument 会使网站加载速度变慢?

在分区 Spark DataFrame 中使用多列是不是会使读取速度变慢?