使用 CountDownTimer 更新 ProgressBar

Posted

技术标签:

【中文标题】使用 CountDownTimer 更新 ProgressBar【英文标题】:Update ProgressBar with a CountDownTimer 【发布时间】:2018-12-24 04:33:35 【问题描述】:

我正在尝试用AsyncTaskCountDownTimer 更新ProgressBar。我没有错误,但ProgressBar 没有更新。

由于MyDownloadTask 扩展AsyncTask 我不需要发布方法或onProgressUpdate()。我的 ProgressBar 在 doInBackground() 中自动更新。

我认为CountDownTimer中的代码没有执行,但我调用的是monCountTimer.start();

这是我的 Java 代码:

public class myDownloadTask extends AsyncTask<Integer, Integer, String> 
    public void setMonCountTimer(CountDownTimer monCountTimer) 
        this.monCountTimer = monCountTimer;
    

    public void setInc(int inc) 
        this.inc = inc;
    

    public void setMaProgressBar(ProgressBar maProgressBar) 
        this.maProgressBar = maProgressBar;
    

    public CountDownTimer getMonCountTimer() 

        return monCountTimer;
    

    public int getInc() 
        return inc;
    

    public ProgressBar getMaProgressBar() 
        return maProgressBar;
    

    protected CountDownTimer monCountTimer;
    private int inc = 0;
    protected ProgressBar maProgressBar;

    public void setMonAct(MainActivity monAct) 
        this.monAct = monAct;
    

    public MainActivity getMonAct() 
        return monAct;
    

    private MainActivity monAct;


    public myDownloadTask(ProgressBar maBarre, MainActivity monActi) 
        this.maProgressBar = maBarre;
        this.monAct = monActi;
    


    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        this.maProgressBar.setProgress(0);

    

    @Override
    protected void onProgressUpdate(Integer... integers) 
        super.onProgressUpdate(integers);

    

    @Override
    protected String doInBackground(Integer... integers) 
        Thread monThread = new Thread(new Runnable() 
            @Override
            public void run() 
                monCountTimer = new CountDownTimer(6000, 1000) 
                    @Override
                    public void onTick(long millisUntilFinished) 
                        myDownloadTask.this.inc++;
                        myDownloadTask.this.getMaProgressBar().setProgress((int) myDownloadTask.this.inc* 100 / (6000 / 1000));
                    
                    @Override
                    public void onFinish() 
                    

                ;
                monCountTimer.start();
            
        );
        return "coucou";
    

主类:

public class MainActivity extends AppCompatActivity  

    private ProgressBar maBarre ;

    public void setMaBarre(ProgressBar maBarre) 
        this.maBarre = maBarre;
    

    public void setLaunchAsync(Button launchAsync) 
        this.launchAsync = launchAsync;
    

    public void setMonHandler(Handler monHandler) 
        this.monHandler = monHandler;
    

    public void setMonCountTimer(CountDownTimer monCountTimer) 
        this.monCountTimer = monCountTimer;
    

    public void setMonTask(myDownloadTask monTask) 
        this.monTask = monTask;
    

    public void setProgressThread(Thread progressThread) 
        ProgressThread = progressThread;
    

    public void setI(int i) 

        this.i = i;
    

    public ProgressBar getMaBarre() 

        return maBarre;
    

    public Button getLaunchAsync() 
        return launchAsync;
    

    public Handler getMonHandler() 
        return monHandler;
    

    public CountDownTimer getMonCountTimer() 
        return monCountTimer;
    

    public String getPROGRESS_BAR_INCREMENT() 
        return PROGRESS_BAR_INCREMENT;
    

    public static int getMessagePreExecute() 
        return MESSAGE_PRE_EXECUTE;
    

    public static int getMessageProgressUpdate() 
        return MESSAGE_PROGRESS_UPDATE;
    

    public static int getMessagePostExecute() 
        return MESSAGE_POST_EXECUTE;
    

    public myDownloadTask getMonTask() 
        return monTask;
    

    public Thread getProgressThread() 
        return ProgressThread;
    

    public int getI() 
        return i;
    

    private Button launchAsync;
    private Handler monHandler ;
    private CountDownTimer monCountTimer ;

    private final String PROGRESS_BAR_INCREMENT="ProgreesBarIncrementId";
    private static final int MESSAGE_PRE_EXECUTE = 1;
    private static final int MESSAGE_PROGRESS_UPDATE = 2;
    private static final int MESSAGE_POST_EXECUTE = 3;
    myDownloadTask monTask;
    Thread ProgressThread ;
    private int i = 0 ;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        maBarre = (ProgressBar) findViewById(R.id.progressBar);
        launchAsync = (Button) findViewById(R.id.button);
        setSupportActionBar(toolbar);


        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            
        );
        this.launchAsync.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 

                monTask = new myDownloadTask(MainActivity.this.maBarre , MainActivity.this);
                monTask.execute();
             
                
        );

    



 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) 

        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in androidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) 
            return true;
    

        return super.onOptionsItemSelected(item);
    


    @Override
    public void onPointerCaptureChanged(boolean hasCapture) 

    


你能帮帮我吗?

【问题讨论】:

嗨。我会尽力提供帮助。最好对可能出现的问题提供更多分析。此外,最好发布 xml 布局。但首先要做的是将问题分成两半。是演示文稿问题吗?还是更新进度条的逻辑有问题?例如,如果将“maBarre.setProgress(50)”添加到 onCreate,进度条会出现在屏幕上吗? 好的。最好使用任何附加信息编辑原始问题。在找到解决方案之前,请勿将其发布在答案中。如果您在答案中发布代码,那么您将被否决,这将降低获得有用响应的可能性,因为较少人看到被否决的问题。你按照我的建议做了吗?尝试在 onCreate 中调用 setProgress(50) 以验证进度是否出现在屏幕上?如果没有出现,则很可能是布局问题。 【参考方案1】:

为您的 XML 文件试试这个。我不知道您要实现什么布局,但是当我执行“setProgress(50);”时在 onCreate 中,使用发布的 XML 文件没有出现任何内容。

我创建了这个 XML 布局,现在进度条看起来很好:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_>

    <Button
        android:id="@+id/button"
        android:layout_
        android:layout_
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/progressBar" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_
        android:layout_
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="140dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_
        android:layout_
        android:layout_gravity="bottom|end"
        android:layout_margin="10dip"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</android.support.constraint.ConstraintLayout>

在onCreate中,添加:

ProgressBar bar = findViewById(R.id.progressBar);
bar.setProgress(50);

测试布局...

还有几个问题:线程已经创建,但是之后必须调用 start()。

 monCountTimer.start();

在public void run()中,代码在做:

  myDownloadTask.this.getMaProgressBar().setProgress((int) 
    myDownloadTask.this.inc* 100 / (6000 / 1000));

永远不要从 Android 中的工作线程更新视图。所有视图都必须在“主线程”(也称为“UI 线程”)上更新

解决此问题的快速方法是:

runOnUiThread(new Runnable() 
    @Override
    public void run() 
        // ...
    
);

我已经进行了上面的更改,现在它运行良好:

public class MainActivity extends AppCompatActivity  

    private ProgressBar maBarre ;

    public void setMaBarre(ProgressBar maBarre) 
        this.maBarre = maBarre;
    

    public void setLaunchAsync(Button launchAsync) 
        this.launchAsync = launchAsync;
    

    public void setMonHandler(Handler monHandler) 
        this.monHandler = monHandler;
    

    public void setMonCountTimer(CountDownTimer monCountTimer) 
        this.monCountTimer = monCountTimer;
    

    public void setMonTask(myDownloadTask monTask) 
        this.monTask = monTask;
    

    public void setProgressThread(Thread progressThread) 
        ProgressThread = progressThread;
    

    public void setI(int i) 

        this.i = i;
    

    public ProgressBar getMaBarre() 

        return maBarre;
    

    public Button getLaunchAsync() 
        return launchAsync;
    

    public Handler getMonHandler() 
        return monHandler;
    

    public CountDownTimer getMonCountTimer() 
        return monCountTimer;
    

    public String getPROGRESS_BAR_INCREMENT() 
        return PROGRESS_BAR_INCREMENT;
    

    public static int getMessagePreExecute() 
        return MESSAGE_PRE_EXECUTE;
    

    public static int getMessageProgressUpdate() 
        return MESSAGE_PROGRESS_UPDATE;
    

    public static int getMessagePostExecute() 
        return MESSAGE_POST_EXECUTE;
    

    public myDownloadTask getMonTask() 
        return monTask;
    

    public Thread getProgressThread() 
        return ProgressThread;
    

    public int getI() 
        return i;
    

    private Button launchAsync;
    private Handler monHandler ;
    private CountDownTimer monCountTimer ;

    private final String PROGRESS_BAR_INCREMENT="ProgreesBarIncrementId";
    private static final int MESSAGE_PRE_EXECUTE = 1;
    private static final int MESSAGE_PROGRESS_UPDATE = 2;
    private static final int MESSAGE_POST_EXECUTE = 3;
    myDownloadTask monTask;
    Thread ProgressThread ;
    private int i = 0 ;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        maBarre = (ProgressBar) findViewById(R.id.progressBar);
        launchAsync = (Button) findViewById(R.id.button);
        //etSupportActionBar(toolbar);


        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            
        );
        this.launchAsync.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 

                monTask = new myDownloadTask(MainActivity.this.maBarre , MainActivity.this);
                monTask.execute();

            
        );

    
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) 

        // getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        return super.onOptionsItemSelected(item);
    


    @Override
    public void onPointerCaptureChanged(boolean hasCapture) 

    


    public class myDownloadTask extends AsyncTask<Integer, Integer, String> 
        public void setMonCountTimer(CountDownTimer monCountTimer) 
            this.monCountTimer = monCountTimer;
        

        public void setInc(int inc) 
            this.inc = inc;
        

        public void setMaProgressBar(ProgressBar maProgressBar) 
            this.maProgressBar = maProgressBar;
        

        public CountDownTimer getMonCountTimer() 

            return monCountTimer;
        

        public int getInc() 
            return inc;
        

        public ProgressBar getMaProgressBar() 
            return maProgressBar;
        

        protected CountDownTimer monCountTimer;
        private int inc = 0;
        protected ProgressBar maProgressBar;

        public void setMonAct(MainActivity monAct) 
            this.monAct = monAct;
        

        public MainActivity getMonAct() 
            return monAct;
        

        private MainActivity monAct;


        public myDownloadTask(ProgressBar maBarre, MainActivity monActi) 
            this.maProgressBar = maBarre;
            this.monAct = monActi;
        


        @Override
        protected void onPreExecute() 
            super.onPreExecute();
            this.maProgressBar.setProgress(0);

        

        @Override
        protected void onProgressUpdate(Integer... integers) 
            super.onProgressUpdate(integers);

        

        @Override
        protected String doInBackground(Integer... integers) 
            Thread monThread = new Thread(new Runnable() 
                @Override
                public void run() 
                    runOnUiThread(new Runnable() 
                        @Override
                        public void run() 
                            monCountTimer = new CountDownTimer(6000, 1000) 
                                @Override
                                public void onTick(long millisUntilFinished) 
                                    myDownloadTask.this.inc++;
                                    myDownloadTask.this.getMaProgressBar().setProgress((int) myDownloadTask.this.inc * 100 / (6000 / 1000));
                                

                                @Override
                                public void onFinish() 
                                

                            ;
                            monCountTimer.start();

                        
                    );
                
            );
            monThread.start();
            return "coucou";
        
    

需要考虑的几个问题:

这里创建的线程比需要的多,代码可以写得更简单。 doInBackground 已经在一个单独的线程上,因此无需在那里创建另一个线程。另外,我相信 CountDownTimer 已经在它自己的线程中运行,所以这里的很多代码可能是不必要的。 完成开发后,请消除所有这些警告。软件开发真的是关于纪律和良好的习惯,只有糟糕的开发人员会忽略警告!完成后执行“分析 -> 检查代码”。

但是你的进度条更新器现在对我来说很好用。

【讨论】:

好的,非常感谢。我认为我在一年前开发了相同的程序,但奇怪的是我不需要 runOnUi runOnUiThread()。这是我的主要困难【参考方案2】:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    tools:context=".MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_
        android:layout_
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_
            android:layout_
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_
        android:layout_
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />





</android.support.design.widget.CoordinatorLayout>

【讨论】:

请提供一个解释性的解决方案。或者确保您的每个解决方案都与其他解决方案根本不同,并且以哪种方式显而易见。我的印象是您应该在问题中添加信息,而不是这些无法解释的代码转储......【参考方案3】:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="81dp"
tools:showIn="@layout/activity_main">

            <Button
            android:id="@+id/button"
            android:layout_
            android:layout_
            android:layout_marginTop="236dp"
            android:text="Button"
            app:layout_constraintEnd_toEndOf="@+id/progressBar"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toStartOf="@+id/progressBar"
            app:layout_constraintTop_toTopOf="parent" />

            <ProgressBar
            android:id="@+id/progressBar"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_
            android:layout_
            android:layout_marginBottom="336dp"
            android:layout_marginEnd="104dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />

    <android.support.constraint.ConstraintLayout
    android:id="@+id/constraintLayout"
    android:layout_
    android:layout_
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    </android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

【讨论】:

我认为问题与线程有关,没有 AsyncTask,它可以工作,但不合适。我想是的,我忘记了指令 monThread.start()。但是有了这个指令,当我触摸按钮时,我的应用程序不起作用 查看我刚刚发布的答案。 XML 布局没有在模拟器中显示进度条。 虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。【参考方案4】:

好的,非常感谢!!!!!!:))

我试过了:

   @Override
    protected String doInBackground(Integer... integers) 
        Thread monThread = new Thread(new Runnable() 
            @Override
            public void run() 
                monCountTimer = new CountDownTimer(6000, 1000) 
                    @Override
                    public void onTick(long millisUntilFinished) 
                        myDownloadTask.this.inc++;
                        myDownloadTask.this.getMaProgressBar().setProgress((int) myDownloadTask.this.inc* 100 / (6000 / 1000));
                    
                    @Override
                    public void onFinish() 
                    

                ;
                monCountTimer.start();
            
            monThread.start();

        );
        return "coucou";
    

使用此代码,我的应用程序刚刚崩溃。

但是runOnUiThread(new Runnable() .... 可以工作

我们使用 2 个线程 ...;( 它没有优化,3 个带有 monCountTimer ,也许,我们可以删除 monThread

“我相信 CountDownTimer 已经在它自己的线程中运行,所以这里的很多代码可能是不必要的。”

我试过了:

@Override
protected String doInBackground(Integer... integers) 
    monCountTimer = new CountDownTimer(6000, 1000) 
        @Override
        public void onTick(long millisUntilFinished) 
        myDownloadTask.this.inc++;
        myDownloadTask.this.getMaProgressBar().setProgress((int) myDownloadTask.this.inc * 100 / (6000 / 1000));
    

        @Override
        public void onFinish() 
    

    ;
    monCountTimer.start();

它不起作用

【讨论】:

好的,但是请停止发布更多的解决方案...只需对我已经发布的解决方案发表评论就可以了。它在我的环境中运行良好,所以我不知道该告诉你什么。你必须给我更多的东西,而不仅仅是它不起作用。日志中有错误吗?尝试将我的文件剪切并粘贴到您的项目中。我刚刚将您的所有代码合并到 1 个类中以使其更快地工作,但它应该按原样运行...也可以使用我的 XML 文件...G'Luck。 是的,我做到了,我昨天测试了你的代码,但是我们必须创建很多线程,这是我要解释和使用 runOnUiThread() 我不能分开我的两个类,因为myDownloadAsyncTask 类 这似乎不是问题的答案。更像是应该在问题中编辑的附加信息。

以上是关于使用 CountDownTimer 更新 ProgressBar的主要内容,如果未能解决你的问题,请参考以下文章

Android CountDownTimer的使用

Android CountDownTimer的使用

Android CountDownTimer的使用

Android Studio 中使用 CountDownTimer 的定时器

CountDownTimer倒计时器的使用

Android 关于 CountDownTimer onTick() 倒计时不准确问题源码分析