【问题标题】:Android Studio - UI Thread not updating with Async TaskAndroid Studio - UI 线程未使用异步任务更新
【发布时间】:2020-07-11 18:34:31
【问题描述】:

我有以下问题:我有一个移动应用程序,单击按钮(“yesbutton”)从异步任务中的服务器获取数据(工作正常)。当该任务正在运行时,我希望我的应用程序显示一个布局(框架布局),我在创建时将其设置为不可见,其中包含一个文本视图和一个圆形进度条。所以我把我设置为可见的行放到我的 Asnyc 任务中的 onPreExecute 方法中,因为我读到这个方法将在 UI 线程上执行。

但这个框架布局仅在我的整个代码运行后显示,而不是在执行时显示。

这是我的代码,我从其中删除了一个我认为不存在问题的块,以使其更具可读性。

public class KeepImageActivity extends AppCompatActivity {

    private static final int PORT_NO = 1234;
    private String pathname;
    private File imgFile;
    private Button yesbutton;
    private Button nobutton;
    private ImageView imageView;
    private FrameLayout frameLayout;


    @SuppressLint("SourceLockedOrientationActivity")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        setContentView(R.layout.activity_keep_image);

        Intent receivedIntent = getIntent();
        pathname = receivedIntent.getStringExtra(CameraActivity.EXTRA_MESSAGE);
        imgFile = new File(pathname);

        imageView = findViewById(R.id.imageViewID);
        yesbutton = findViewById(R.id.yesbuttonID);
        nobutton = findViewById(R.id.discardbuttonID);

        nobutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onDiscard(pathname);
            }
        });
        yesbutton.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void onClick(View view) {
                onYes();
            }
        });

        frameLayout = findViewById(R.id.framelayout);
        frameLayout.setVisibility(View.GONE);
        showImage();
    }

    //method to show a picture in an ImageView
    private void showImage() {
        imgFile = new File(pathname);
        Bitmap bitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
        imageView.setRotation(90);
        imageView.setImageBitmap(bitmap);
    }

    private void onDiscard(String pathname) {
        //....not relevant
}


    @RequiresApi(api = Build.VERSION_CODES.O)
    private void onYes() {

        //doInBackground just fetches data and writes to jpg
        class ConnectTask extends AsyncTask<Void, Void, Void> {
            @Override
            protected Void doInBackground(Void... voids) {
                //doing stuff (connection to server and downloading image ("image_from_server"))
            }

            @Override
            //here my frameLayout is not being set to Visible, at least not DURING execution.
            protected void onPreExecute() {
                frameLayout.setVisibility(View.VISIBLE);

            }

            @Override
            protected void onPostExecute(Void aVoid) {

            }

            @Override
            protected void onProgressUpdate(Void... values) {
            }
        }



        ConnectTask connect =  new ConnectTask();
        Void[] param = null;

        //execute Async task
        connect.execute(param);


        //wait until picture on Phone
        File xaifile = new File(Environment.getExternalStorageDirectory() + "/image_from_server.jpg");
        while (true){
            if (xaifile.exists()){
                break;
            }
        }
        replacePicture(xaifile);
    }


    //here i replace the picture/bitmap in the ImageView with another one (that just came from server)
    private void replacePicture(File xaifile) {
        Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + "/image_from_server.jpg");
        imageView.setRotation(90);
        imageView.setImageBitmap(bitmap);

        //finished loading, I commented this line to see if my Layout would show afterwards. It does.
        //frameLayout.setVisibility(View.INVISIBLE);

        //delete both files, not needed anymore
        xaifile.delete();
        imgFile.delete();
    }

//AND IT SEEMS LIKE HERE IS THE MOMENT THAT THE UPDATE TO THE UI IS SHOWN. WHY??
}

【问题讨论】:

  • while (true){...} 循环在 UI 线程上运行,它会阻塞它(它会阻塞 onPreExecute 的执行)。
  • @Titus 好吧,我改变了,我将“frameLayout.setVisibility(View.VISIBLE) 行移出异步任务并在循环之前(所以现在我什至从 UI 调用它)线程)。但它仍然没有显示......

标签: java android user-interface ui-thread


【解决方案1】:

写这部分:

//wait until picture on Phone
    File xaifile = new File(Environment.getExternalStorageDirectory() + "/image_from_server.jpg");
    while (true){
        if (xaifile.exists()){
            break;
        }
    }
    replacePicture(xaifile);

在 onPostExecute 中

目前你正在阻塞主线程。

【讨论】:

  • 是的,谢谢!但是为什么当我将“setVisible”行放在循环之前它不起作用?它应该将 laout 设置为可见,因为它是在 UI 线程上调用的,并且在我进入 while(true) 循环之前,不是吗?
  • 当你调用 Step1>connect.execute(param); //New Thread stared 紧接着你调用了这一行: Step2> File xaifile = new File(Environment.. 这将在微秒内执行,主线程被阻塞。因为这是在主线程上。然后在你的异步任务中你调用step3>frameLayout.setV .. 这将在 step2 完全执行但未找到文件时执行,循环不会终止,并且 step3 只会在循环完成时调用。在你的情况下,在异步任务 postExecute 之后创建文件。希望这个有帮助!
猜你喜欢
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
  • 1970-01-01
  • 2014-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多