2016-03-17 117 views
0

看似簡單的要求 - 從IntentService更新UI。在下面的拍攝中,當點擊Start Service按鈕時,我需要在TextView以上顯示ProgressBar,並在延遲之後刪除ProgressBar無法從IntentService更新UI

AVD Screenshot

找到很多答案對SO,但不知何故無法依然破解它。我從this瞭解到LocalBroadcastManager是一個很好的選擇。我也嘗試過this(與Handler s的方法),但它也未能顯示ProgressBar。最後,根據this回答,這裏是我結束了。到目前爲止,我所管理的輸出僅僅是Toast s,在完成所有記錄之後連續出現。

非常感謝,如果你能指出我出錯的地方,現在已經掙扎了相當一段時間了。提前謝謝了!

MainActivity更新

public class MainActivity extends AppCompatActivity 
{ 
    private static final String TAG = "MainActivity"; 
    private ProgressBar pb; 
    private MyBroadcastReceiver myBroadcastReceiver; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     pb = (ProgressBar) findViewById(R.id.pb); 
     myBroadcastReceiver = new MyBroadcastReceiver(); 

     LocalBroadcastManager.getInstance(this).registerReceiver(myBroadcastReceiver, new IntentFilter("ACTION")); 
    } 

    private void updateUI(boolean show) 
    { 
     if (show) 
      pb.setVisibility(View.VISIBLE); 
     else 
      pb.setVisibility(View.GONE); 
//  Toast.makeText(this, "UI Updated...", Toast.LENGTH_LONG).show(); 
    } 

    public void startIt(View view) 
    { 
     Intent intent = new Intent(this, NanisIntentService.class); 
     startService(intent); 
    } 

    public class MyBroadcastReceiver extends BroadcastReceiver 
    { 
     @Override 
     public void onReceive(final Context context, Intent intent) 
     { 
      String action = intent.getAction(); 
      Log.e(TAG, "In onReceive(): " + action); 
      if (action.equals("ACTION")) 
      { 
       updateUI(true); 
      } // of if (action = "ACTION") 
      else if (action.equals("NOITCA")) 
      { 
       updateUI(false); 
      } // of else of if (action = "ACTION") 
     } // of onReceive() 
    } // of class MyBroadcastReceiver 
} 

IntentService更新

public class NanisIntentService extends IntentService 
{ 
    private static final String TAG = "NanisIntentService"; 

    public NanisIntentService() 
    { 
     super("NanisIntentService"); 
    } 

    @Override 
    protected void onHandleIntent(Intent intent) 
    { 
     Log.e(TAG, "In onHandleIntent(): Intent is being serviced"); 
     LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("ACTION")); 
     int i = 0; 
     while (i <= 50) 
     { 
      try 
      { 
       Thread.sleep(50); 
       i++; 
       Log.e("", "" + i); 
      } catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 
     } 
    } 

    @Override 
    public void onDestroy() 
    { 
     super.onDestroy(); 
     LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("NOITCA")); 
     Log.e(TAG, "In onDestroy(): The service has been destroyed"); 
    } 
} 

    @Override 
    public void onStart(Intent intent, int startId) 
    { 
     super.onStart(intent, startId); 
     LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("ACTION")); 
    } 

    @Override 
    public void onDestroy() 
    { 
     super.onDestroy(); 
     LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("NOITCA")); 
     Log.e(TAG, "In onDestroy(): The service has been destroyed"); 
    } 
} 

    @Override 
    public void onDestroy() 
    { 
     super.onDestroy(); 
     LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("NOITCA")); 
     Log.e(TAG, "In onDestroy(): The service has been destroyed"); 
    } 
} 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    tools:context="testing.com.myintentservice.MainActivity"> 

    <ProgressBar 
     android:id="@+id/pb" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_above="@+id/tv" 
     android:layout_centerHorizontal="true" 
     android:indeterminate="true" 
     android:visibility="gone"/> 

    <TextView 
     android:id="@+id/tv" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerInParent="true" 
     android:text="Hello IntentService!" 
     android:textColor="#1298CE" 
     android:textSize="32sp"/> 

    <Button 
     android:id="@+id/bt" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentBottom="true" 
     android:layout_centerHorizontal="true" 
     android:text="Start Service" 
     android:onClick="startIt"/> 
</RelativeLayout> 

AndroidManifest

<application 
     android:allowBackup="true" 
     android:icon="@mipmap/ic_launcher" 
     android:label="@string/app_name" 
     android:supportsRtl="true" 
     android:theme="@style/AppTheme"> 
     <activity android:name=".MainActivity"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN"/> 

       <category android:name="android.intent.category.LAUNCHER"/> 
      </intent-filter> 
     </activity> 
     <service android:name="testing.com.myintentservice.NanisIntentService"/> 
    </application> 

回答

2

首先,你佔用主應用程序線程〜2.5秒。這會在這段時間內凍結您的用戶界面。 不要這樣做

其次,您在〜2.5秒之前撥打updateUI()一次,之後撥打一次。由於您在此期間正在綁定主應用程序線程,因此與拖延後連續調用updateUI()有相同的視覺效果。 updateUI()切換ProgressBar的可見性,因此兩個呼叫將相互抵消,使您處於與您開始時相同的狀態。

我需要在唯一的TextView上方顯示一個ProgressBar,並在延遲後刪除ProgressBar。

顯示一個ProgressBar持續2.5秒,無論任何實際工作正在進行,都是相當隨意的。

話雖這麼說,叫updateUI()一次,然後用pb.postDelayed()安排一個Runnable運行2500毫秒之後,那裏的run()方法的調用RunnableupdateUI()第二次。這樣可以避免阻塞主應用程序線程,因此它允許第一個updateUI()調用生效,同時仍然給您持續2.5秒的時間。

+0

感謝您的快速反應,@CommonsWare!對不起,但我錯過了提及這是一個_experiment_,_PoC_--因此,而不是延遲2.5秒,將有一個不確定的互聯網下載,在此期間,我需要顯示'ProgressBar'。你的建議是否仍然有效?非常感謝您是否可以在可能的情況下詳細闡述解決方案。乾杯! –

+1

@NarayanaJ:「你的建議是否仍然有效?」 - 假設「ProgressBar」的持續時間取決於服務,那麼你可以按照這種方式開始。爲「show」和「hide」使用兩個不同的'LocalBroadcastManager'事件。在短期內,延遲服務,以服務所做的「假工作」的形式出現。然後,您可以用真正的工作來替換假工作,並且您的'ProgressBar'邏輯不必更改。 – CommonsWare

+0

請在我的原始問題中檢查更新的代碼。我做的是: - 將'假工作'移動到'IntentService' - 設置2廣播行動,一個顯示和一個隱藏'ProgressBar'我也不確定Runnable調用你最初提出的建議)仍然應該提出,也不應該如此。 「ProgressBar」仍然不顯示。請回復。 –

0

非常感謝,@CommonsWare!最後讓它工作。它需要兩個接收器爲兩個不同的動作,我發現here

對於那些尋找最後的工作代碼的好處...

結果屏幕: - 點擊處理後後

赦免代碼中的任何複製粘貼鬼,它畢竟是在PoC,儘管功能。

+0

提供的鏈接不起作用。 – user3705478

+0

@ user3705478,不知道它是如何從塗膏消失的。當我獲得一些空閒時間時,將使用代碼更新這篇文章。直到那時,請忍受。 –