Android: Update progress bar through CountDownTimer - android

I've to just show a count down fragment at certain trigger which includes a progress bar that reduces count on tick of a countdown timer.
I'm using following simple steps:
Call startTimer() in onCreateView of fragment.
In startTimer() define a CountDownTimer class where onTick method reduces progress of a ProgressBar and onFinish shows a Toast message.
Start this timer on UI thread using getActivity().runOnUIThread()
Problem is the timer executes but ProgressBar keeps showing indeterminate progress i.e. it remains unchanged. Toast is also seen at the finish but nothing changes for progress bar.
What's going wrong here?
Below is the current code:
public class IncomingRequestFragment extends Fragment {
private OnFragmentInteractionListener mListener;
private FrameLayout root;
private CountDownTimer mCountDownTimer;
private ProgressBar mProgressBar;
public IncomingRequestFragment() {
// Required empty public constructor
}
public static IncomingRequestFragment newInstance(String param1, String param2) {
IncomingRequestFragment fragment = new IncomingRequestFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
int progress=25;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
root = (FrameLayout) inflater.inflate(R.layout.fragment_incoming_request, container, false);
mProgressBar = (ProgressBar) root.findViewById(R.id.countDown);
progress = mProgressBar.getMax();
mProgressBar.setIndeterminate(false);
mProgressBar.setProgress(progress);
startTimer();
return root;
}
private void startTimer() {
mCountDownTimer = new CountDownTimer(25000,1000) {
#Override
public void onTick(long millisUntilFinished) {
mProgressBar.setProgress(progress--);
Log.d("count",String.valueOf(progress));
}
#Override
public void onFinish() {
Toast.makeText(getContext(),"You just missed a trip!",Toast.LENGTH_SHORT).show();
}
};
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mCountDownTimer.start();
}
});
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
Layout XML:
<FrameLayout 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"
tools:context="com.taxiwaxidriver.ui.fragments.IncomingRequestFragment">
<ProgressBar
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/countDown"
android:layout_margin="60dp"
android:max="25"
android:progressTint="#android:color/holo_blue_dark"
android:progressBackgroundTint="#android:color/holo_blue_dark"
android:progress="25"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:padding="12dp"
android:weightSum="2"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#color/white"
android:text="REJECT"
android:id="#+id/rideLater"
android:background="#drawable/rounded_button_left"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="ACCEPT"
android:textColor="#color/white"
android:background="#drawable/rounded_button_right"
android:id="#+id/rideNow"/>
</LinearLayout>
</FrameLayout>
Output of above code is:
05-07 10:49:05.623 21455-21455 D/count: 24
05-07 10:49:06.626 21455-21455 D/count: 23
05-07 10:49:07.636 21455-21455 D/count: 22
05-07 10:49:08.653 21455-21455 D/count: 21
.
.
.
05-07 10:49:28.917 21455-21455 D/count: 1<br>

mistake was missing the style attribute for ProgressBar defined in XML
style=""?android:attr/progressBarStyleHorizontal"
Thanks to pskink's comment

Related

Show "loading layout" while sending requests

I have activity and when it is created it sends some requests, so it takes time to load this activity.
Is it possible to show "loading layout" while requests are proceeding?
I tried something like this, but it doesn't work:
setContentView(R.layout.loading);
sendRequests();
setContentView(R.layout.main);
To accomplish this, you could add a "loading layout" to your main layout.
Something like this:
<FrameLayout
android:id="#+id/loading_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Loading stuff" />
</FrameLayout>
Then when it is time to show your loading layout you can do:
FrameLayout loadingLayout = findViewById(R.id.loading_layout);
loadingLayout.setVisibility(View.VISIBLE);
When you want to hide it simply:
loadingLayout.setVisibility(View.GONE);
You will want to make sure that you do network requests off of the main thread, and return to the main thread whenever it is time to update the UI (i.e. show/hide the loading layout).
You can add a progress bar in activity or fragment.
If you are using Retrofit or etc., use this approach:
Set the progressbar visible before request
and invisible it when onResponse or onFailure called
binding.progressBar.setVisibility(View.VISIBLE);
// request
call.enqueue(new Callback<MovieResponse>() {
#Override
public void onResponse(Response<MovieResponse> response) {
Log.d(TAG, "onResponse is called");
// invisible progress bar here
binding.progressBar.setVisibility(View.INVISIBLE);
if (!response.isSuccess()) {
Log.d(TAG, "No Success");
}
mMovieList = response.body().getMovies(); // <- response is null here
mMovieAdapter.notifyDataSetChanged();
}
#Override
public void onFailure(Throwable t) {
Log.i(TAG, "onFailure is called");
// invisible progress bar here
binding.progressBar.setVisibility(View.INVISIBLE);
Toast.makeText(getActivity(), "Failed !", Toast.LENGTH_LONG).show();
}
});
You can create common class for custom progress dialog,
public class CustomProgressDialog extends Dialog {
public CustomProgressDialog(#NonNull Context context) {
super(context);
init(context);
}
public CustomProgressDialog(#NonNull Context context, int themeResId) {
super(context, themeResId);
init(context);
}
protected CustomProgressDialog(#NonNull Context context, boolean cancelable, #Nullable OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
init(context);
}
void init(Context context) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().getDecorView().getRootView().setBackgroundResource(android.R.color.transparent);
getWindow().setDimAmount(0.1f);
getWindow().getDecorView().setOnApplyWindowInsetsListener((v, insets) -> {
insets.consumeSystemWindowInsets();
return insets;
});
View view = LayoutInflater.from(context).inflate(
R.layout.dialog_custom, null
);
setContentView(view);
setCancelable(false);
setCanceledOnTouchOutside(false);
}
}
dialog_custom.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="10dp">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:indeterminateTint="#color/colorPrimary" />
</RelativeLayout>
Declare this class in your activity or parent activity to use in every child classes,
public class BaseFragment extends Fragment {
protected CustomProgressDialog mDialog;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDialog = new CustomProgressDialog(requireActivity());
}
}
To show dialog before your api call
mDialog.show();
To dismiss dialog in response or error
mDialog.dismiss();

Android check box tik mark disappear randomly when moving from one fragment to another using android-material-stepper

Instead of getting checkbox like this(i am getting it only few times randomly when moving from on fragment to another).
I am getting like this(checkbox is still true but only tik mark is missing randomly)
I am using onSaveInstanceState and onViewStateRestored. The problem is the checkbox tik mark only disappears and comes back few times but the state of checkbox is still selected i see blue color around all the selected check boxes that selected color doesn't go away only the tik mark goes away and comes back randomly.
Layout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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_width="match_parent"
android:layout_height="match_parent">
<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_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="#+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:drawableLeft="#drawable/ic_tv"
android:text="TV"
android:theme="#style/CheckBoxTheme"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Tv" />
</android.support.constraint.ConstraintLayout>
</ScrollView>
My Fragment:
public class StepFragmentTwo extends Fragment implements BlockingStep {
private static final String CLICKS_KEY = "clicks";
private static final String TAG = "ADERVERTISMENT";
private int i = 0;
FragmentManager fm = getFragmentManager();
CheckBox c;
Boolean tv = false ;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(getLayoutResId(), container, false);
c = (CheckBox)v.findViewById(R.id.checkBox);
//initialize your UI
return v;
}
protected int getLayoutResId() {
return getArguments().getInt(String.valueOf(R.layout.step2));
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(CLICKS_KEY, i);
super.onSaveInstanceState(outState);
if(outState!=null) {
outState.putBoolean("c", c.isChecked());
}
}
#Override
public void onViewStateRestored(#Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if(savedInstanceState!=null) {
tv = savedInstanceState.getBoolean("c");
}
}
#Override
public void onResume() {
super.onResume();
c.setChecked(tv);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
public void onNextClicked(final StepperLayout.OnNextClickedCallback callback) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (c.isChecked()) {
tv = true;
}
SharedPreferences shared = getActivity().getSharedPreferences("Mypref", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = shared.edit();
editor.putBoolean("tv", tv);
editor.apply(); // This line is IMPORTANT !!!
callback.goToNextStep();
}
}, 200L);
}
#Override
#UiThread
public void onCompleteClicked(final StepperLayout.OnCompleteClickedCallback callback) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
callback.complete();
}
}, 2000L);
}
public static StepFragmentTwo newInstance(#LayoutRes int layoutResId) {
Bundle args = new Bundle();
args.putInt(String.valueOf(R.layout.step2), layoutResId);
StepFragmentTwo fragment = new StepFragmentTwo();
fragment.setArguments(args);
return fragment;
}
#Override
public VerificationError verifyStep() {
//return null if the user can go to the next step, create a new VerificationError instance otherwise
return null;
}
#Override
public void onSelected() {
//update UI when selected
}
#Override
public void onError(#NonNull VerificationError error) {
//handle error inside of the fragment, e.g. show error on EditText
}
public void onBackClicked(StepperLayout.OnBackClickedCallback callback) {
//Toast.makeText(this.getContext(), "Your custom back action. Here you should cancel currently running operations", Toast.LENGTH_SHORT).show();
callback.goToPrevStep();
}
}
In short you can do,
#Override
public void onResume() {
super.onResume();
SharedPreferences shared = getActivity().getSharedPreferences("Mypref", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = shared.edit();
tv = editor.getBoolean("tv", tv);
c.setChecked(tv);
}

Android Studio Progress Bar Move

I put a progress bar in my android studio project , and want it to move , but i don't know how to do that . I tried to look for tutorials on YouTube and follow along , but that didn't work out for me. Then i looked on google for tutorials but that didn't work for me . When i search them up i only see tutorials with the circle loading bars and I want mine to be horizontal . I only know where to start the loading bar but i really want to know how to make it move and then go into the game . I don't have any code because when i seen that it wasn't working i just deleted it . If anybody has a good tutorial or code that could help me i would appreciate very much . Thanks.
have very easy way to use progress bar within whole code
custom_progressbar.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
android:id="#+id/progressbar_view"
android:layout_width="#dimen/_70sdp"
android:layout_height="#dimen/_70sdp"
android:indeterminate="true"
android:padding="#dimen/_10sdp" />
</RelativeLayout>
CustomProgressBar.java
public class CustomProgressBar extends Dialog {
Activity activity;
public CustomProgressBar(Activity act) {
super(act);
this.activity = act;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.custom_progressbar);
setCancelable(false);
// set backgroung transparent
getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
}
}
and apply whenever you want activity or fragment
public CustomProgressBar customProgressBar;
customProgressBar = new CustomProgressBar(context);
customProgressBar.show();
public class MainActivity extends AppCompatActivity {
private ProgressBar progressBar;
private TextView loading;
private int progressStatus = 0;
private Handler pHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
loading = (TextView) findViewById(R.id.loading);
new Thread(new Runnable() {
#Override
public void run() {
while (progressStatus < 100) {
progressStatus ++;
android.os.SystemClock.sleep(50);
pHandler.post(new Runnable() {
#Override
public void run() {
progressBar.setProgress(progressStatus);
}
});
}
pHandler.post(new Runnable() {
#Override
public void run() {
loading.setText("COMPLETE");
}
});
}
}).start();
}
This code works. You should be able to use the default XML code for the ProgressBar. You will need to add the elements, for example, the actual progress bar in the visual design. You will need to add an extra '}' at the end I think.
Check this: Infact you have to code for the horizontal progress bar movement and set its progress, it's specially used in downloading to show percentage of operation completion.
XML code:
<ProgressBar
android:id="#+id/progressBar1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="23dp"
android:layout_marginTop="20dp"
android:indeterminate="false"
android:max="100"
android:minHeight="50dp"
android:minWidth="200dp"
android:progress="1" />
java code:
public class MainActivity extends Activity {
private ProgressBar progressBar;
private int progressStatus = 0;
private TextView textView;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
textView = (TextView) findViewById(R.id.textView1);
//Long operation by thread
new Thread(new Runnable() {
public void run() {
while (progressStatus < 100) {
progressStatus += 1;
//Update progress bar with completion of operation
handler.post(new Runnable() {
public void run() {
progressBar.setProgress(progressStatus);
textView.setText(progressStatus+"/"+progressBar.getMax());
}
});
try {
// Sleep for 200 milliseconds.
//Just to display the progress slowly
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items
//to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="50">
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="false"
android:id="#+id/Bar1"
android:max="10"
android:padding="15dp"
android:paddingTop="5dp"
android:paddingRight="20dp"
android:paddingLeft="20dp">
</ProgressBar>
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="startProgress"
android:text="Start" />
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/progressBar2"
android:layout_gravity="center_horizontal" />
</LinearLayout>
MainActivity.java
package com.example.dell.vlakna;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import static com.example.dell.vlakna.R.layout.activity_main;
public class MainActivity extends Activity {
private ProgressBar bar;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(activity_main);
bar = (ProgressBar) findViewById(R.id.Bar1);
}
public void startProgress(View view) {
bar.setProgress(0);
new Thread(new Task()).start();
}
class Task implements Runnable {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bar.setProgress(value);
}
}
}
}
this code run good.

Android: When watching a youtube video fullscreen I press back and the Activity finish

I've read all around the way of leaving fullscreen from a YouTube video is by pressing back, but in my Activity it's not working like this but I'd like it to.
I post you the code:
public class MainActivity extends YouTubeFailureRecoveryActivity {
public static String prefix = "https://gdata.youtube.com/feeds/api/playlists/";
public static String sufix = "?v=2&alt=jsonc";
private String myPlayList = "PLZGKlf2ZwY7ua0C2oeUaXQKeLKNGy3mkh";
private VideosListFragment videosFragment;
// The next video to play
private Video actualVideo;
// This is the handler that receives the response when the YouTube read
private Handler responseHandler;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videosFragment = (VideosListFragment) getFragmentManager().findFragmentById(R.id.videosListView);
getUserYouTubeFeed();
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider,
YouTubePlayer player, boolean wasRestored) {
if (!wasRestored) {
player.loadVideo(actualVideo.getVideoId());
}
}
#Override
protected YouTubePlayer.Provider getYouTubePlayerProvider() {
return (YouTubePlayerFragment) getFragmentManager().findFragmentById(
R.id.youtube_fragment);
}
public void getUserYouTubeFeed() {
responseHandler = new Handler() {
public void handleMessage(Message msg) {
populateListWithVideos(msg);
};
};
// We start a new AsyncTask that does its work on its own thread
// We pass in a handler that will be called when the task has finished
LoadPlayListElements bgTask = new LoadPlayListElements(responseHandler);
bgTask.execute(myPlayList);
}
/**
* This method retrieves the Library of videos from the task and passes them
* to our ListView
*
* #param msg
*/
private void populateListWithVideos(Message msg) {
Library lib = (Library) msg.getData().get(
LoadPlayListElements.LIBRARY);
VideosAdapter videos = new VideosAdapter(this, lib.getVideos());
videosFragment.setListAdapter(videos);
}
#Override
protected void onStop() {
// Make sure we null our handler when the activity has stopped
responseHandler = null;
super.onStop();
}
public void setVideo(Video _item, boolean _activate) {
actualVideo = _item;
if (_activate){
YouTubePlayerFragment fragment = (YouTubePlayerFragment) getFragmentManager()
.findFragmentById(R.id.youtube_fragment);
if (fragment != null && fragment.isInLayout()) {
fragment.initialize(DeveloperKey.DEVELOPER_KEY, this);
}
}
}
}
and the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin" >
<fragment
android:id="#+id/videosListView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginTop="?android:attr/actionBarSize"
class="com.vivoenmimundo.sc2hotsepicreplays.ui.phone.fragment.VideosListFragment" >
</fragment>
<fragment
android:name="com.google.android.youtube.player.YouTubePlayerFragment"
android:id="#+id/youtube_fragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:layout_gravity="center_vertical"/>
</LinearLayout>
Any idea? I've tried to not do anything too strange, just copy/paste from YouTube's API examples.
It was, as said before, the correct behaviour - because the player was inside a fragment, I had to catch the back button with:
#Override
public void onBackPressed() {
if (fullScreen){
videoPlayer.setFullscreen(false);
} else{
super.onBackPressed();
}
}
and set my "fullScreen" boolean like this:
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider,
YouTubePlayer player, boolean wasRestored) {
if (!wasRestored) {
showPlayer();
videoPlayer = player;
videoPlayer.setOnFullscreenListener(new OnFullscreenListener() {
#Override
public void onFullscreen(boolean _isFullScreen) {
fullScreen = _isFullScreen;
}
});
videoPlayer.loadVideo(actualVideo.getVideoId());
}
}
thanks all!
Step1 : Follow Answer 16 by Nhano
Step2 : add below line in your Menifest YoutubeActivity tag.
android:configChanges="orientation|screenSize"
this solution worked for me..
You could try to detect the back button press and custom define what it does.
// Sets functionality of the hard buttons on the device
#Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK) {
// Custom define what you want to happen
}
return true;
}

Trouble getting handle to TextView in android callback

I am trying to make a remote control for a Google TV.
I want to change the text I have in a layout (TextView statusText) with connected when the device has successfully connected. But I get an exception when I try to do this:
"07-07 22:42:20.870: E/AndroidRuntime(5750):android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
"Appreciate any help/pointers
Here is my MainActivity.java and main.xml:
MainActivity.java:
package uk.co.mypack.gtvremote;
//imports removed for paste
public class MainActivity extends Activity implements ClientListener{
private AnymoteSender anymoteSender;
private TextView statusText;
protected AnymoteClientService mAnymoteClientService;
private static String statusPrefix = "Status: ";
private Context mContext;
private ProgressBar progressBar;
private Handler handler;
private TouchHandler touchPadHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
progressBar = (ProgressBar) findViewById(R.id.a_progressbar);
progressBar.setVisibility(View.VISIBLE);
mContext = this;
ImageButton upArrowButton = (ImageButton) findViewById(R.id.upArrow);
ImageButton leftArrowButton = (ImageButton) findViewById(R.id.leftArrow);
ImageButton centreButton = (ImageButton) findViewById(R.id.centreButton);
ImageButton rightArrowButton = (ImageButton) findViewById(R.id.rightArrow);
ImageButton downArrowButton = (ImageButton) findViewById(R.id.downArrow);
upArrowButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_UP);
}
});
leftArrowButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT);
}
});
centreButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_CENTER);
}
});
rightArrowButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
}
});
downArrowButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN);
}
});
handler = new Handler();
// Bind to the AnymoteClientService
Intent intent = new Intent(mContext, AnymoteClientService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
statusText = (TextView) findViewById(R.id.statusText);
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
/*
* ServiceConnection listener methods.
*/
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mAnymoteClientService = ((AnymoteClientService.AnymoteClientServiceBinder) service)
.getService();
mAnymoteClientService.attachClientListener(MainActivity.this);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mAnymoteClientService.detachClientListener(MainActivity.this);
mAnymoteClientService = null;
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onConnected(AnymoteSender anymoteSender) {
if (anymoteSender != null) {
// Send events to Google TV using anymoteSender.
// save handle to the anymoteSender instance.
this.anymoteSender = anymoteSender;
//THIS IS WHERE I AM TRYING TO SET THE TEXTVIEW
TextView localStatusText = (TextView) findViewById(R.id.statusText);
localStatusText.setText(statusPrefix + "Connected to GoogleTV");
//ABOVE IS WHERE I AM TRYING TO SET THE TEXTVIEW
// Attach touch handler to the touchpad view
touchPadHandler = new TouchHandler(
findViewById(R.id.touchPad), Mode.POINTER_MULTITOUCH, anymoteSender);
} else {
statusText.setText(statusPrefix + "Connection attempt failed, cant find send handler");
//attempt to connect again?
//attemptToConnect();
}
// Hide the progressBar once connection to Google TV is established.
handler.post(new Runnable() {
public void run() {
progressBar.setVisibility(View.INVISIBLE);
}
});
}
#Override
public void onDisconnected() {
// show message to tell the user about disconnection.
statusText.setText(statusPrefix + "Disconnected");
// Try to connect again if needed. This may be need to be done via button
attemptToConnect();
this.anymoteSender = null;
}
#Override
public void onConnectionError() {
// show message to tell the user about disconnection.
statusText.setText(statusPrefix + "Connection error encountered");
// Try to connect again if needed.
attemptToConnect();
this.anymoteSender = null;
}
#Override
protected void onDestroy() {
if (mAnymoteClientService != null) {
mAnymoteClientService.detachClientListener(this);
}
unbindService(mConnection);
super.onDestroy();
}
public void attemptToConnect()
{
//stub to invoke connection attempt
}
private void sendKeyEvent(final int keyEvent) {
// create new Thread to avoid network operations on UI Thread
if (anymoteSender == null) {
Toast.makeText(MainActivity.this, "Waiting for connection",
Toast.LENGTH_LONG).show();
return;
}
anymoteSender.sendKeyPress(keyEvent);
}
}
Main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/control_message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="#dimen/padding_medium"
android:text="#string/control_msg"
android:textSize="90dp"
tools:context=".MainActivity" />
<LinearLayout
android:id="#+id/middlePanel"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/statusText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Status: Disconnected - startup"
android:textSize="20dp" />
<ImageView
android:id="#+id/touchPad"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="#drawable/greysquare"
/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical" >
<ImageButton
android:id="#+id/upArrow"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#drawable/blackuparrow" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<ImageButton
android:id="#+id/leftArrow"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#drawable/blackleftarrow" />
<ImageButton
android:id="#+id/centreButton"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#drawable/emptycircle"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" />
<ImageButton
android:id="#+id/rightArrow"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#drawable/blackrightarrow" />
</LinearLayout>
<ImageButton
android:id="#+id/downArrow"
android:layout_width="150dp"
android:layout_height="150dp"
android:background="#drawable/blackdownarrow" />
</LinearLayout>
</LinearLayout>
<ProgressBar
android:id="#+id/a_progressbar"
style="#android:style/Widget.ProgressBar.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
The onConnected() callback is not called on the Main UI thread, but on a separate thread that is used by the Service. So it is not able to access the TextView created in Main UI thread. What you should do is create a Handler in the main UI thread and then use that handler to post a runnable that makes changes to the TextView. You can read more about Handlers on the Android developer site.

Categories

Resources