【问题标题】:Calling SetRefreshing(false) outside main thread is not allowed. Workaround?不允许在主线程外调用 SetRefreshing(false)。解决方法?
【发布时间】:2017-05-15 13:38:01
【问题描述】:

在我的 android 应用程序中,我想使用 SwipeRefreshLayout 刷新我的 ListView,并且在 onRefresh() 方法中我想为此任务创建一个新线程。由于我的刷新方法必须获取一堆文件,当从主线程调用时它会暂时冻结应用程序,这破坏了使用 SwipeRefrehLayout 的整个目的(在应用程序刷新时通知用户,何时完成这样做)。

最后一部分是我遇到的麻烦。我想在获取文件后调用 SwipeRefreshLayout.setRefreshing(false) 来停止刷新动画。我这样做的方法是在新线程内的同一刷新方法的末尾调用 setRefreshing,但问题是我收到一个错误提示

Only the original thread that created a view hierarchy can touch its views.

我正在考虑是否有办法创建线程结束侦听器,那将是最好的方法,但不幸的是,我已经研究了几个星期没有解决方案。

是否有每个人都可以使用 SwipeRefreshLayout 的明显替代方案?任何帮助将不胜感激。

这里有一些代码,以防我的解释很糟糕(这是可以理解的)

            public void onRefresh() {

                // This method performs the actual data-refresh operation.

                //I used refreshLayout.getContext() instead of the "this" keyword since "this" would return an OnRefreshListener instead of my actual context
                //I pass my refreshLayout to the constructor so it knows which to stop animating at the end.
                Thread thread = new Thread (new Refresher(refreshLayout.getContext(), refreshLayout));
                thread.start();

                //I use this to update the adapter in my ListView after it has been refreshed by my Refresher thread.
                if (listView != null)
                    listView.setAdapter(new CategoryListAdapter(Categories, refreshLayout.getContext()));
            }

我的进修课: `

public class Refresher implements Runnable {

    SwipeRefreshLayout refreshLayout;
    Context context;

    public Refresher (Context c, SwipeRefreshLayout rl) {

        refreshLayout = rl;
        context = c;

    }

    @Override
    public void run() {

        //Call the method that fetches the files.
        ((CategoryMenu) context).RefreshCategories(CategoryMenu.SaveDirectory);

        //Here's where my error gets thrown.
        refreshLayout.setRefreshing(false);
        //I understand why, but I don't know a good workaround.

    }

}

`

【问题讨论】:

  • 使用异步任务
  • @Denny 这很完美!您能否将此添加为答案,以便我可以将此问题设置为已解决?
  • 当然,我已经把它作为答案发布了

标签: java android multithreading android-layout


【解决方案1】:
MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                refreshLayout.setRefreshing(false);
            }
        });

试试 runOnUiThread,希望能解决你的问题

【讨论】:

  • 不幸的是,这仍然使应用程序在刷新时冻结。 @Denny 的正确答案是使用 AsyncTask,但这是一条评论,因此我无法将其设置为已解决:( 我仍然添加了投票,因为您让我学习了一些很好的技巧,例如使用 ActivityClass.this 来获取上下文例如在 onClickListener 中:)
【解决方案2】:

为了保持 UI 流畅,您可以使用 AsyncTask,它会在后台执行操作,您可以获得进度更新并在任务完成时收到通知。 来自android dev site的示例

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    protected Long doInBackground(URL... urls) {
        int count = urls.length;
        long totalSize = 0;
        // do some long running operation on the background
        for (int i = 0; i < count; i++) {
            totalSize += Downloader.downloadFile(urls[i]);
            publishProgress((int) ((i / (float) count) * 100));
            // Escape early if cancel() is called
            if (isCancelled()) break;
        }
        // pass the result to onPostExecute()
        return totalSize;
    }

    protected void onProgressUpdate(Integer... progress) {
        setProgressPercent(progress[0]);
    }

    protected void onPostExecute(Long result) {
        // update the UI when you're done
        showDialog("Downloaded " + result + " bytes");
    }
}

【讨论】:

    猜你喜欢
    • 2015-10-12
    • 2021-06-18
    • 1970-01-01
    • 2015-01-10
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多