Problem with a Handler(ImageView) - android

I want to show 2 images (one when connected and the second when disconnected) and i'm using a handler to handle that, however, i'm not having any of the 2 images showen, don't know why :.
private Runnable handleUpdateStatus = new Runnable()
{
Boolean mRegistered;
public void run()
{
ImageView statusImageDisplay = (ImageView)findViewById(R.id.connected);
if (mRegistered)
{
statusImageDisplay.setImageDrawable(getResources().getDrawable(R.drawable.connected));
Log.i("CONNECTED","IMAGE SET");
}
else
{
statusImageDisplay.setImageDrawable(getResources().getDrawable(R.drawable.disconnected));
Log.i("DISCONNECTED","IMAGE SET");
}
}
};
Changing image code excerpt:
public void onRegistrationDone(String localProfileUri, long expiryTime) {
updateStatus("Enregistré au serveur.");
Log.d("SUCCEED","Registration DONE");
mRegistered = true;
mRegistrationUpdateHandler.removeCallbacks(handleUpdateStatus);
mRegistrationUpdateHandler.postDelayed(handleUpdateStatus, 4000);
}
What to do when the registration failed? this code:
public void onRegistrationFailed(String localProfileUri, int errorCode,String errorMessage) {
updateStatus("Enregistrement échoué. Veuillez vérifier vos paramètres.");
Log.d("ERROR REGISTRATION",errorMessage);
mRegistered = false;
mRegistrationUpdateHandler.removeCallbacks(handleUpdateStatus);
mRegistrationUpdateHandler.postDelayed(handleUpdateStatus, 2000);
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/sipLabel"
android:textSize="20sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<ImageView android:id="#+id/connected" android:src="#drawable/connected"
android:layout_below="#id/sipLabel"
android:layout_width="fill_parent" android:scaleType="center"
android:layout_height="fill_parent" android:layout_weight="0.35"
android:gravity="center" android:visibility="invisible" />
</LinearLayout>
Any idea please of how solving this problem ?
Thank you very much.

You (must) have your mRegistered variable declared twice, and while you're setting the value for the global one (the one declared inside your Activity), you examine the value of the other one, declared inside your handleUpdateStatus Runnable.
You should clean up your code a bit:
remove the mRegistration declaration
from your Runnable implementation,
// Boolean mRegistered;
set the image drawable via resource
id,
and it will work:
private boolean mRegistered;
private Runnable handleUpdateStatus = new Runnable()
{
public void run()
{
ImageView statusImageDisplay = (ImageView) findViewById(R.id.connected);
if (mRegistered)
{
statusImageDisplay.setImageResource(R.drawable.connected);
Log.i("CONNECTED", "IMAGE SET");
}
else
{
statusImageDisplay.setImageResource(R.drawable.disconnected);
Log.i("DISCONNECTED", "IMAGE SET");
}
}
};
This is all you need to change (assuming, that your layout really contains an image with id connected).
Update
As about mRegistrationUpdateHandler, you should declare it as a global variable of your Activity (either final or initialized inside the onCreate method):
private final Handler mRegistrationUpdateHandler = new Handler();
or
private Handler mRegistrationUpdateHandler;

Related

Unable to update UI from IntentService

A seemingly simple requirement - to update UI from an IntentService. In the shot below, when the Start Service button is clicked, I need to show a ProgressBar above the only TextView and after a delay, remove the ProgressBar.
Found a lot of answers on SO, but somehow unable to still crack it. I understand from this that LocalBroadcastManager is a good way to go. I have also tried following this, (an approach with Handlers), but it fails to show the ProgressBar too. Finally, based on this answer, here's what I have ended up with. The output I've managed so far is just the Toasts appearing in succession, after all the logging is done.
Greatly appreciate if you could point out where I am going wrong, been struggling for quite some time now. Many thanks in advance!
MainActivity updated
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 updated
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>
First, you are tying up the main application thread for ~2.5 seconds. This will freeze your UI during this period of time. Do not do this.
Second, you are calling updateUI() once before the ~2.5 seconds, and once after. Since you are tying up the main application thread during that time, this will have the same visual effect as calling updateUI() twice in succession after the delay. updateUI() toggles the ProgressBar visibility, so two calls will cancel each other out, leaving you in the same state as you started.
I need to show a ProgressBar above the only TextView and after a delay, remove the ProgressBar.
Showing a ProgressBar for 2.5 seconds, irrespective of any actual work being done, is rather arbitrary.
That being said, call updateUI() once, then use pb.postDelayed() to schedule a Runnable to run 2500 milliseconds later, where the run() method in the Runnable calls updateUI() the second time. This avoids you blocking the main application thread, so it allows the first updateUI() call to take effect, while still giving you the 2.5-second duration.
Thanks so much, #CommonsWare! Finally got it to work. It needed two receivers for the two different actions, which I discovered here.
For the benefit of those looking for the final working code...
MainActivity
NanisIntentService
Result screens:- after clicking and after processing
Pardon any copy-paste ghosts in the code, it is after all a PoC, albeit functional.

Why does my Android app's view only update under a specific circumstance?

I am working on an Android app that is behaving oddly. One of the first things this app does upon start up, is to start a listening thread that listens to a "server" app, on the same device, to get data. Once this data is received by the listening thread, I use it to update the main view. This, however only works if my app is started after the server app.
First a few details. My app and the server app are on the same device. They communicate with each other via UDP (the server app is a port of a Windows application). My app uses fragments, but the view I want to update is not within a fragment. Now some code.
content_main.xml
<RelativeLayout>
<LinearLayout>
<ImageView
android:id="#+id/my_image_id"
android:src="#drawable/my_image" />
</LinearLayout>
<LinearLayout>
<!-- fragment code here -->
</LinearLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState){
Listener myListener = new Listener(this);
Thread listenerThread = new Thread(myListener);
listenerThread.setName("My Listener Thread");
listenerThread.start();
}
}
Listener.java
public class Listener implements Runnable {
public Listener (Activity mainActivity) {this.mainActivity = mainActivity;}
private Activity mainActivity;
private ImageView myImageView;
private NewData newData;
#Override
public void run(){
while(true){
// Here is where my app gets the data from the server via UDP.
// This always works, I am always getting the correct data.
myImageView = (ImageView) mainActivity.findViewById(R.id.my_image_id);
mainActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
if(newData == 1){
myImageView.setImageResource(R.drawable.new_image_01);
} else if(newData == 2){
myImageView.setImageResource(R.drawable.new_image_02);
} else {
myImageView.setImageResource(R.drawable.error_image);
}
}
});
}
}
}
Like I said, if I start my app after the server app, then this all works perfectly. The images always changes when the new data changes. However, if I start my app before the server app, or if I restart the server app while my app is still running, then the images never changes, even though I am still getting the correct data from the server app.
What can I do to make sure the view can update at any time?
EDIT: I moved where I get the view to outside of the while loop (as a test) and now the code doesn't work at all.
I gave it a try. apparently your code is working alright, if the thread starts after the activity is been initialized, i don't really know how your server app works so i tried to mimic something like this.
public class TestThreadActivity extends AppCompatActivity {
private Button restart_Button;
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_thread);
Toolbar toolbar = (Toolbar) findViewById(R.id.my_custom_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initializeUI();
}
private void initializeUI() {
restart_Button = (Button) findViewById(R.id.TestThreadActivity_restart_button);
imageView = (ImageView) findViewById(R.id.TestThreadActivity_imageView);
final Listener myListener = new Listener(this);
restart_Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imageView.setImageResource(R.drawable.piccolo);
final Thread listenerThread = new Thread(myListener);
listenerThread.setName("My Listener Thread");
listenerThread.start();
}
});
}
public class Listener implements Runnable {
public Listener (Activity mainActivity) {this.mainActivity = mainActivity;}
private Activity mainActivity;
private ImageView myImageView;
int newData = 0;
#Override
public void run(){
while(true){
// Here is where my app gets the data from the server via UDP.
// This always works, I am always getting the correct data.
newData = (new Random()).nextInt(3);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myImageView = (ImageView) mainActivity.findViewById(R.id.TestThreadActivity_imageView);
mainActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
System.out.println("newData: "+newData);
if(newData == 1){
myImageView.setImageResource(R.drawable.gohan);
} else if(newData == 2){
myImageView.setImageResource(R.drawable.goku);
} else {
myImageView.setImageResource(R.drawable.piccolo);
}
}
});
}
}
}
}
activity_test_thread.xml
<LinearLayout 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:orientation="vertical"
tools:context="activities.list.first.TestThreadActivity">
<include layout="#layout/my_custom_toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/TestThreadActivity_restart_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_weight="0.5"
android:text="Start"
android:contentDescription="this will restart the thread"
android:textAllCaps="false" />
</LinearLayout>
<ImageView
android:id="#+id/TestThreadActivity_imageView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="#drawable/gohan" />
</LinearLayout>
</LinearLayout>
Output

Text View not getting updated. Seems fine while debugging

I have 2 virtually identical textviews in a layout that are updated by 2 similar bits of code. When the app runs (whether emulator or phone) one is updated but the other is not - but when run the same way in debug mode they are both updated. I've done lots of searching online, read lots of questions and answers and have tried various ways to update the textview, but the weird thing is this combination: it works in debug but not live, but another texview and a canvas are updated ok. Even a log message (placed in the same if clause as this textview update) works in debug but not when run on emulator (other log messages are being
displayed ok).
The layout also has a canvas used for a simple game and the relevant code is within the running of that game. The canvas is updated by a repeating runnable. I wanted to add a time limit to the game so thought I'd simply mark the start time and then check in the runnable the time since the start. The textview is intended to show the seconds passing - and it works in debug! Abbreviated version of code below.
Maybe it's something about timing, something not having time to run properly? It doesn't need another runnable, does it, seeing as it's managing to update the other textview ok? Should you do runnables within runnables?
Any help or guidance appreciated.
Layout
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/trees2"
android:orientation="vertical"
tools:context=".GameActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal" >
<TextView
android:id="#+id/score"
android:layout_width="54dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical|center_horizontal"
android:text="0"
android:background="#drawable/border"
android:textAppearance="?android:attr/textAppearanceLarge" >
</TextView>
<TextView
android:id="#+id/countdown"
android:layout_width="54dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical|center_horizontal"
android:text="0"
android:background="#drawable/border"
android:textAppearance="?android:attr/textAppearanceLarge" >
</TextView>
</LinearLayout>
<TextView
android:id="#+id/the_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="" />
<couk.jit.drawing.GameBoard
android:id="#+id/the_canvas"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="20dip" />
</LinearLayout>
GameBoard.java
public class GameBoard extends View {
public GameBoard(Context context, AttributeSet aSet) {
super(context, aSet);
p = new Paint();
sprite1 = new Point(-1,-1);
m = new Matrix();
bm1 = BitmapFactory.decodeResource(getResources(), R.drawable.b1);
sprite1Bounds = new Rect(0,0, bm1.getWidth(), bm1.getHeight());
bm = BitmapFactory.decodeResource(getResources(),R.drawable.go_sign);
}
synchronized public boolean didItHitTarget() {
if .... return true;
else ... return false;
}
#Override
synchronized public void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, getWidth(), getHeight(), p);
canvas.drawBitmap(bm3, sprite3.x, sprite3.y, null);
}
}
GameActivity.java
public class GameActivity extends Activity implements OnTouchListener {
private static final int FRAME_RATE = 20;
long startTime;
int timerCount = 0;
int score = 0;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
h.postDelayed(new Runnable() {
#Override
public void run() {
initGfx();
}
}, 1000);
}
synchronized public void initGfx() {
Point p1, p2;
p1 = getStartPoint();
((GameBoard)findViewById(R.id.the_canvas)).setSprite1(p1.x, p1.y);
((View)findViewById(R.id.the_canvas)).setOnTouchListener(this);
frame.removeCallbacks(frameUpdate);
frame.postDelayed(frameUpdate, FRAME_RATE);
}
private Runnable frameUpdate = new Runnable() {
#Override
synchronized public void run() {
if (state == GameState.Ready)
updateReady();
if (state == GameState.Running)
updateRunning();
}
synchronized public void updateReady() {
frame.removeCallbacks(frameUpdate);
((GameBoard)findViewById(R.id.the_canvas)).invalidate();
startTime = System.nanoTime(); //set game start time
frame.postDelayed(frameUpdate, FRAME_RATE);
}
synchronized public void updateRunning() {
frame.removeCallbacks(frameUpdate);
if (((GameBoard)findViewById(R.id.the_canvas)).didItHitTarget()) {
score = score + 1;
//This works fine
((TextView)findViewById(R.id.score)).setText(Integer.toString(score));
Point p1;
p1 = getStartPoint();
((GameBoard)findViewById(R.id.the_canvas)).setSprite1(p1.x, p1.y);
}
float deltaTime = (System.nanoTime() - startTime) / 100000000000.0f;
int j = (int) deltaTime;
if ((int)deltaTime > timerCount) {
timerCount = timerCount + 1;
//This works in debug but does not update live
((TextView)findViewById(R.id.countdown)).setText(Integer.toString(timerCount));
Log.i(TAG, "Updating countdown");
}
((GameBoard)findViewById(R.id.the_canvas)).invalidate();
frame.postDelayed(frameUpdate, FRAME_RATE);
}
};
This was my solution in case anyone interested (or can still suggest better way!).
Going from blackbelt's point that certain parts of the code are simply not being entered, I thought that, although I couldn't find the reason, it must be something to do with the complexity of the timer clock combined with android's thread handling. So I created the timer using a separate thread, as in code here:
Android update TextView in Thread and Runnable

Best practices to handle multiple presses on buttons

I have found as a common issue in any of my apps that the user may accidentally perform several clicks on the same button causing multiple executions of the onClick listener logic. Typically, my business logic for those onClickListeners usually consists of launching of a heavy-process AsynTask that performs an HTTP request and later modifies the UI.
My way to prevent multiple executions of the asyntask was to unable the button at the beginning of the listener method and enable it again as a first statement of the onPostExecute. That has generally worked for me or at least I have not received any issue regarding to this situation.
Recently, a colleague has pointed me a potential problem of this unable-enable-button method. As shown in the below code that consists of two buttons '+' and '-', quick and alternative presses on those buttons causes a crash the application by an ArrayOutOfIndex exception.
That fact has made me think about my way of managing the concurrency of the onClickListener events and if it is really possible to have the situation in which a second asyntask may be launches prior to the finalization of the first asyntask using the aforementioned method.
What are your suggestions to handle this situation?
For those suggestions that recommend to apply some logic rejecting the second launches of the asyntask until the completion of the first asyntask, is it is really worth to generally apply that logic for a common used application in which the buttons perform an http request?.
CrashActivity.java
public class CrashActivity extends Activity {
private int mNumbers[] = { 1, 2, 3, 4, 5 };
private int position = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView result = (TextView) findViewById(R.id.resultTextView);
final Button minusBtn = (Button) findViewById(R.id.minus_button);
final Button plusBtn = (Button) findViewById(R.id.plus_button);
minusBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
minusBtn.setEnabled(false);
plusBtn.setEnabled(true);
result.setText("" + mNumbers[--position]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
minusBtn.setEnabled((position > 0));
}
});
plusBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
plusBtn.setEnabled(false);
minusBtn.setEnabled(true);
result.setText("" + mNumbers[position++]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
plusBtn.setEnabled((position <= 4));
}
});
minusBtn.setEnabled(false);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/minus_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="-" />
<Button
android:id="#+id/plus_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="+" />
<TextView
android:id="#+id/resultTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="hello stackoverflow!" />
</LinearLayout>
A solution that would guarantee that both methods do not try to update the UI at the same time would be to synchronize the UI update code. You could either create a synchronized method or an Object that acts as a lock for a block of code. Example:
public synchronized void updateUI() {
// ...
}
or
private Object mLock = new Object();
public void updateUI() {
// ...
synchronized (mLock) {
// Critical code here.
}
// ...
}
Expanding this to make sure that task 1 completes before task 2, completes before task 3, etc., you would need to somehow keep track of which started first. Note: synchronization occurs on the UI thread in this example.
private List<AsyncTask> mRunningTasks = new ArrayList<AsyncTask>();
public void onClick(View v) {
v.setEnabled(false);
if (v == task1View) {
Task1 task = new Task1();
mRunningTasks.add(task);
task.execute();
}
else if (v == task2View) {
Task2 task = new Task2();
mRunningTasks.add(task);
task.execute();
}
// ...
}
// Copy and paste for each necessary task.
private Task1 extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... v) {
// Run task 1 code here.
while (this != mRunningTasks.get(0)) {
wait(1000);
}
return v[0];
}
protected void onPostExecute(Void v) {
updateUI();
mRunningTasks.remove(0);
task1View.setEnabled(true);
}
}
public void updateUI() {
// UI update code here.
}

Update GUI when a boolean in a class changes

I'm trying to have my Activity update an ImageView whenever a boolean value changes in another class.
Therefore i have some sort of timer that starts on my first onCreate()
private void startTimer() {
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 2000); // first run after 2 secs
}
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
connectionControl.checkNetworkState();
System.out.println("online?: " + connectionControl.isOnline());
mHandler.postDelayed(this, 15000); // repeat every x/1000 secs
}
};
My class ConnectionControl has a boolean, that gets set to either true or false whether my app can reach a specific http-host.
Now my question is: how can i achieve a automatic change on the ImageView in my Activity to display the boolean's value?
I already looked at Observer-Pattern, EventListener, BroadcastReciever but I'm stuck at finding the right solution.
Also, i want to use the listening in other Activities.
What has worked so far was starting/stopping the timer-thing for each activity and have the ImageView update inside the run() method. But my guess is, there has to be a way around the redundancy.
I think you are in search of AsyncTask , by using it you can made a call to webservice asynchronously and after the successful call to the webservice, we can process the fetched data.
Just go through this article: http://developer.android.com/resources/articles/painless-threading.html.
I think you needs this: (from android.com)
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
For more info about AsyncTask , here is link: http://developer.android.com/reference/android/os/AsyncTask.html
Here is how I did it.
I made a layout file for the custom titlebar thing, that has an ImageView.
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageView android:id="#+id/title_statusimg"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:src="#drawable/connected" android:layout_centerVertical="true"
android:layout_alignParentRight="true" />
</RelativeLayout>
</merge>
I include this in every activities layout file i want to use it.
<include layout="#layout/titlebar" />
Also, i made a StatusActivity that extends Activity. It receives a Broadcast that is send from whenever an background thread detects a change in the connectivity to the webserver.
public class StatusActivity extends Activity {
private String CONNECTION_STATUS = "app.CONNECTION_STATUS";
private ImageView conn;
#Override
protected void onResume() {
super.onResume();
IntentFilter iFilter = new IntentFilter(CONNECTION_STATUS);
registerReceiver(mBroadcastReceiver, iFilter);
conn = (ImageView) findViewById(R.id.title_statusimg);
if (ConnectionControl.isOnline()) {
conn.setImageResource(R.drawable.connected);
} else {
conn.setImageResource(R.drawable.nconnected);
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mBroadcastReceiver);
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectionControl.isOnline()) {
conn.setImageResource(R.drawable.connected);
} else {
conn.setImageResource(R.drawable.nconnected);
}
}
};
}
Every Activity that shall use this Status-Image extends StatusActivity instead of Activity.
Hope i covered everything, atleast for me it's working.

Categories

Resources