【问题标题】:App crash when calling a method after a delay延迟后调用方法时应用程序崩溃
【发布时间】:2020-04-01 12:07:12
【问题描述】:

我正在尝试在 OnCreate 中执行 doit() 方法,等待 5 秒以允许该方法的功能完全加载,然后在等待函数中调用 tester() 方法。 该应用程序正常运行,没有延迟,并显示“TextView”,这是函数完成之前文本框的输出,我想等待 5 秒,直到 doit() 完成加载,然后显示来自测试仪的 texx 的内容() 等待之后。任何帮助,将不胜感激。 下面链接的图片是崩溃输出和应用正常运行。

Crash output

App working without delay, but doesn't output textbox content because it hasn't loaded


public class AppHome extends AppCompatActivity implements PopupMenu.OnMenuItemClickListener {
    TextView texx;
    private ArrayList<String> al;
    private ArrayAdapter<String> arrayAdapter;
    private int i;

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

        new doit().execute();

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
           tester();
            }
        }, 5000);
    }
        public void tester() {
            texx = findViewById(R.id.text1);
            String text = texx.getText().toString();

            //String num = text;
            String[] str = text.split(",");
            final ArrayList al = new ArrayList<String>(Arrays.asList(str));

            arrayAdapter = new ArrayAdapter<>(this, R.layout.item, R.id.helloText, al);

            SwipeFlingAdapterView flingContainer = findViewById(R.id.frame);


            registerForContextMenu(flingContainer);


            flingContainer.setAdapter(arrayAdapter);

            flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener() {
                @Override
                public void removeFirstObjectInAdapter() {
                    // this is the simplest way to delete an object from the Adapter (/AdapterView)
                    Log.d("LIST", "removed object!");
                    al.remove(0);
                    arrayAdapter.notifyDataSetChanged();
                }

                @Override
                public void onLeftCardExit(Object dataObject) {
                    //Do something on the left!
                    //You also have access to the original object.
                    //If you want to use it just cast it (String) dataObject
                    Toast.makeText(AppHome.this, "left", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onRightCardExit(Object dataObject) {
                    Toast.makeText(AppHome.this, "right", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onAdapterAboutToEmpty(int itemsInAdapter) {
                    // Ask for more data here
                    al.add("XML ".concat(String.valueOf(i)));
                    arrayAdapter.notifyDataSetChanged();
                    Log.d("LIST", "notified");
                    i++;
                }

                @Override
                public void onScroll(float scrollProgressPercent) {
                }
            });

            // Optionally add an OnItemClickListener
        /*
        flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener() {
            @Override
            public void onItemClicked(int itemPosition, Object dataObject) {

            }
        });

         */

        }

        public class doit extends AsyncTask<Void, Void, String> {
            @Override
            protected String doInBackground(Void... voids) {
                String words = "";
                try {
                    Document doc = Jsoup.connect("https://screenscrape4top40.000webhostapp.com/").get();
                    words = doc.text();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return words;
            }

            @Override
            public void onPostExecute(String words) {
                super.onPostExecute(words);
                texx.setText(words);

            }
        }


        public void showPopup (View v){
            PopupMenu popup = new PopupMenu(this, v);
            popup.setOnMenuItemClickListener(this);
            popup.inflate(R.menu.dropdown_menu1);
            popup.show();
        }

        @Override
        public boolean onMenuItemClick (MenuItem item){
            switch (item.getItemId()) {
                case R.id.item1:
                    Toast.makeText(this, "Item 1 clicked", Toast.LENGTH_SHORT).show();
                    return true;
                case R.id.item2:
                    Toast.makeText(this, "Item 2 clicked", Toast.LENGTH_SHORT).show();
                    return true;
                case R.id.item3:
                    Toast.makeText(this, "Item 3 clicked", Toast.LENGTH_SHORT).show();
                    return true;
                case R.id.item4:
                    Toast.makeText(this, "Item 4 clicked", Toast.LENGTH_SHORT).show();
                    return true;
                default:
                    return false;
            }
        }
    }



【问题讨论】:

  • 您只是在 5 秒后设置变量 texx。线程在此之前完成,所以 texx 在那时为空。
  • 我可以建议两件事,首先将 AsyncTask 移到它自己的类文件中(或使类静态)。否则,您最终会泄漏Context。此外,AsyncTask is official deprecated。处理并发有一些更好的解决方案。 Kotlin 有协程。 Java 和 Kotlin 有 RxJava。作为一些例子。

标签: java android android-studio crash delay


【解决方案1】:

在 onCreate() 中移动以下行,在 setContentView() 之后:

texx = findViewById(R.id.text1);

【讨论】:

  • 这是正确的。此外,一个好的解决方案是将tester() 调用移出处理程序并将其放入onPostExecute。如果调用需要 6 秒,无论出于何种原因,数据都还没有准备好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 2014-05-06
  • 1970-01-01
相关资源
最近更新 更多