从 json 检索图像时出现 "The application may be doing too much work on its main thread" 错误

On retrieving images from json get "The application may be doing too much work on its main thread" error

我想使用 AsyncTask 在后台检索照片。我以 base64 编码形式将照片作为字符串获取。但是,我有 "The application may be doing too much work on its main thread" 错误消息。

我的activity:

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, ItemClickHandler{

    private RecyclerView recyclerView;
    private RecyclerViewAdapter adapter;
    private LayoutManager layoutManager;

    private ArrayList<Device> devices;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_action_bar);

        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);

        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        adapter = new RecyclerViewAdapter(devices, this);
        recyclerView.setAdapter(adapter);

        initImages();
    }

    private void initImages() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                for(int i = 0; i < devices.size(); i++){
                    final int pos = i;
                    GetImageJSON getImage = new GetImageJSON(MainActivity.this){
                        @Override
                        protected void onPostExecute(final String result) {
                            Log.d(TAG, result);

                            if(pos <= recyclerView.getLayoutManager().getChildCount()){
                                adapter.updateItem(ImageManager.convertToBitmap(result), pos);
                            }
                        }
                    };
                    getImage.execute(ConnectionConfig.getUserItemImage(devices.get(i).getId()));
                }
            }
        };
        thread.start();
    }
}

GetImageJSON class:

public class GetDataJSON extends AsyncTask<String, Void, String> {

    private static String charset = "UTF-8";

    @Override
    protected String doInBackground(String... args) { 
        String result = parseJSONString(args[0]);
        if(!result.isEmpty()){
            try{
                JSONObject json = new JSONObject(result);
                JSONObject jsonObject = json.getJSONObject(ConnectionConfig.TAG_RESULT);
                String base64String = jsonObject.getString("image");
                Log.d(TAG, base64String);
                Bitmap bitmap = ImageManager.convertToBitmap(base64String);
                bitmap = ImageManager.scaleDownBitmap(bitmap, context);
                Log.d(TAG, "got result: " + result);
                return ImageManager.convertBitMapToString(bitmap);
            }catch (JSONException e){
                e.printStackTrace();
            }
        }

        return result;
    }

    public static String parseJSONString(String... args){
        String result = "";
        InputStream inputStream = null;

        Log.d(TAG, args[0]);
        try {
            URL url = new URL(args[0]);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

            conn.setDoOutput(false);
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept-Charset", charset);
            conn.setConnectTimeout(15000);
            conn.connect();

            try {
                InputStream in = new BufferedInputStream(conn.getInputStream());
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String line;
                while ((line = reader.readLine()) != null) {
                    result += line;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            conn.disconnect();
        } catch (Exception e) {
            Log.d(TAG, "Exception", e);
        } finally {
            try{
                if(inputStream != null)
                    inputStream.close();
            }catch(Exception e){
                Log.d(TAG, e.getMessage());
            }
        }

        return result;
    }
}

我找不到任何解决方案。请推荐任何一个。我如何优化检索数据的过程。

如果没有你的代码的可运行版本,我无法确定,但我猜想有行 ImageManager.convertToBitmap(result)onPostExecute() 中导致了 "too much work on main thread" 问题。 onPostExecute() 中发生的任何事情都发生在主线程上,因此您希望该方法尽可能轻便。正如 SRB 所建议的那样,您可以通过使用 doInBackground return 位图而不是需要转换回位图的字符串来避免这种情况。请注意,要更改 return 类型,您需要在两个地方将 String 更改为 Bitmap

public class GetDataJSON extends AsyncTask<String, Void, Bitmap> {

    @Override
    protected Bitmap doInBackground(String... args) {
        // TODO return the bitmap
    }

    //...the rest of your code

}

另外,您的代码似乎还有改进的余地。这些内容与您的问题没有直接关系,但最好理解。

  1. 当你调用getImage.execute()时,GetDataJSONclass的doInBackground方法将被执行。 doInBackground 方法始终在后台线程上运行(参见 "The 4 steps" 部分 here),因此没有理由在 initImages() 方法中创建新线程。

  2. 使用 recyclerview 的好处之一是当 recyclerview 出现在屏幕上时,您不需要加载所有内容。如果有屏幕外的视图,则可以在用户滚动到它们时创建这些视图。通过在创建 activity 时检索所有图像,您将失去该优势。

  3. 有像 Picasso and Glide 这样的图像加载库可以为您提取背景图像。我不知道您的网站 API 是什么样子,但如果您可以,使用预先存在的库可以让快速处理占位符、缓存、调整大小等问题变得简单。