如何从线程更新 UI?

Posted

技术标签:

【中文标题】如何从线程更新 UI?【英文标题】:How to updated UI from thread? 【发布时间】:2013-10-12 07:22:19 【问题描述】:

我在 android app 中使用线程时遇到了一些问题。

我有 Activity1.java,它有一些从 sql lite 数据库获取数据并将其显示在活动上的功能。我有一种方法 Load() 填充一些微调器静态和一些来自数据库。第二个微调器值取决于第一个下拉菜单,依此类推。它还可见/不可见一些 UI 控件

场景 1:-

如果我们在 oncreate() 方法上调用 Load() 函数,那么活动会变慢。

场景2:-(线程)

如果我们在 oncreate() 方法的线程内调用 Load() 函数并且我使用 runOnUiThread 或 Handler.post 来更新 ui 控件,那么它将跳过该代码,在代码中走得更远,而我的其他值有些错误或来不及。

场景 3:-(异步)

如果我们在 oncreate() 方法上调用 Aysnc 中的 Load() 函数,那么我必须从异步任务中不断更新 ui。 UI 中的更新只允许在 onPostExecute(Result) 和 onProgressUpdate(Progress...) 上进行,但我如何从 async 连续更新 ui。

 @Override
protected void onCreate(Bundle savedInstanceState) 
           BindStaticValues();
    GetCalculationOptions();

 public void BindStaticValues()


    //standard 
    BindStandard(); //static spinner (not db)           

    //Spinner 1
    array1 = new ArrayList<ObjectMaterial>();
    Adapter1 = new DescriptionAdapter(this,
            android.R.layout.simple_spinner_item,
            array1 );
    Adapter1 
    .setDropDownViewResource(android.R.layout.simple_spinner_item);
    sp1.setAdapter(Adapter1 );

    //Spinner 2
    array2 = new ArrayList<ObjectMaterial>();
    Adapter2 = new DescriptionAdapter(this,
            android.R.layout.simple_spinner_item,
            array2 );
    Adapter2 
    .setDropDownViewResource(android.R.layout.simple_spinner_item);
    sp2.setAdapter(Adapter2 );




public void GetCalculationOptions ()


    progressCalcualtionOptions = ProgressDialog.show(context, getString(R.string.progressCalcualtionOptionsTitle),
            getString(R.string.progressCalcualtionOptionsMessage), true);

    new Thread(new Runnable() 
        public void run() 
            try 
            
                LoadValuesforFirstTime(false, false, false); //main load method (Need Updating UI)
                isFirstOpen=false;
            
            catch (Exception e)    
                //Log.d(Constants.TAG, e.getMessage());
                e.printStackTrace();
            

            if (progressCalcualtionOptions != null)
            
                progressCalcualtionOptions.dismiss();
                progressCalcualtionOptions=null;
                   


        
    ).start();




private void LoadValuesforFirstTime(Boolean FromMaterial,
        Boolean FromLangugae, Boolean FromCountry) 


    ChangeVisibility(); // it will change visibility of some controls 

    FillSpinner1(TypeofMaterial); //fill first spinner 1

    FillSpinner2(ObjectMaterial); //fill first spinner 2 (take values from spinner 1 or manipulate values in spinner 1)



private void ChangeVisibility() 

// it will change visibility of some controls 

    runOnUiThread(new Runnable() 

        public void run() 


            relat_heightPipe.setVisibility(View.GONE);
            relat_PipeDiameter.setVisibility(View.GONE);
            relat_WidthPipe.setVisibility(View.GONE);
            relat_length.setVisibility(View.GONE);

            relat_lblMediumHeatCapacity.setVisibility(View.GONE);
            relat_lblMediumDensity.setVisibility(View.GONE);

        
    );


private void FillSpinner1(String TypeofMaterial) 

          array1 = DB_Manager.All(); //get from db

    h.post(new Runnable() 

            public void run() 
                Adapter1.clear();
                for (ObjectMaterial object : array1 )
                    Adapter1.add(object);   

                Adapter1.notifyDataSetChanged();
            
        );


       private void FillSpinner2(String TypeofMaterial) 


          array2 = DB_Manager.All1(spinner1.getSelectedItemPosition()); //get from db

    h.post(new Runnable() 

            public void run() 
                Adapter2.clear();
                for (ObjectMaterial object : array2 )
                    Adapter2.add(object);   

                Adapter2.notifyDataSetChanged();
            
        );

现在,问题是:-

当活动打开时,GetCalculationOptions 调用一个线程来填充所有微调器值。在此它调用 LoadValuesforFirstTime() 函数。在这里我用 db 和 ui 做所有事情。 这里 changevisibility 更改某些控件的可见性,FillSpinner1 填充从 db 获取值,在主 ui 线程内刷新适配器,填充 Spinenr2 根据微调器 1 中的选定值从 db 获取值,但在微调器 1 中找不到值,因为它直到没有填充现在它是另一个线程,现在我们必须从 LoadValuesforFirstTime() 函数不断更新 UI。

任何人,请帮助我或建议我任何其他选择来实现这一目标。

【问题讨论】:

【参考方案1】:

调用你的方法

runOnUiThread(new Runnable()
        public void run() 

                  write your method here 

        
     );

来自doInbackground 方法。

【讨论】:

如果我在主 ui 线程上运行所有功能,那么活动会变慢。 只需在负责更新ui的run方法中调用该方法。

以上是关于如何从线程更新 UI?的主要内容,如果未能解决你的问题,请参考以下文章

从 UI 线程强制 GUI 更新

如何在android一条单独线程,更新ui ?

从后台线程更新 UI 是一种不好的做法,为啥? [关闭]

即使从主线程调用更新,UI 也不会更新

从 JavaFX 中的不同线程更新 UI

如何做到在子线程更新 UI?