android update custom view - android

Hello I am new programmer and I have a custom view in my app that i try to make to redraw itself after i give him new data i tried using invalidate but it seem to not work I'm not sure if the problem is the way i update the data or the way i try to make the view redraw itself. any help will be appreciated.
view:
public class BlackJackView extends View {
private PlayerView playerView, computerView;
private BlackJackGame game;
private Context contex;
public void setPlayer(BlackJackPlayer player) {
playerView = new PlayerView(contex, player);
}
public void setComputer(BlackJackPlayer computer) {
computerView = new PlayerView(contex, computer);
}
public BlackJackView(Context context) {
super(context);
init(context);
}
public BlackJackView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public BlackJackView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
this.contex = context;
game = new BlackJackGame();
playerView = new PlayerView(contex, game.getPlayer());
computerView = new PlayerView(contex, game.getComputer());
}
public void init(BlackJackGame game) {
this.game = new BlackJackGame(game.getPlayer().getName(),game.getPlayer().getMoney());
playerView = new PlayerView(contex, game.getPlayer());
computerView = new PlayerView(contex, game.getComputer());
this.invalidate();
}
#Override
public void onDraw(Canvas canvas) {
playerView.onDraw(canvas);
computerView.onDraw(canvas);
}
}
activity:
public class BlackJackActivity extends Activity {
private UsersDataSource dataSource;
private List<User> values;
private BlackJackView view;
private BlackJackGame game;
private int userID;
private int playerMoney;
private String playerName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
game = new BlackJackGame();
view = new BlackJackView(this);
view.setPlayer(game.getPlayer());
setContentView(R.layout.black_jack_activity);
GetId(savedInstanceState);
GetPlayerData();
view = (BlackJackView) findViewById(R.id.blackJackView);
view.init(game);
}
private void GetId(Bundle savedInstanceState) {
if (savedInstanceState == null) {
Bundle extras = getIntent().getExtras();
if (extras == null) {
userID = -1;
} else {
userID = extras.getInt("ID");
}
} else {
userID = (int) savedInstanceState.getSerializable("ID");
}
}
private void GetPlayerData() {
//data base open
dataSource = new UsersDataSource(this);
dataSource.open();
//get list of database
values = dataSource.getAllUsers();
playerName = values.get(userID).getUsername();
playerMoney = (int) values.get(userID).getTokens();
}
#Override
protected void onResume() {
dataSource.open();
super.onResume();
}
#Override
protected void onPause() {
dataSource.close();
super.onPause();
}
}

Related

Searchable Spinner not working in android

I had a simple spinner which i working perfect. Now I wanted to change it that a user can able to search the items in it. By following the below code I have done changes.
Sample code
//Gradle
compile 'com.toptoche.searchablespinner:searchablespinnerlibrary:1.3.1'
//activity_main.xml
<com.toptoche.searchablespinnerlibrary.SearchableSpinner
android:id="#+id/searchable_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
// In main activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SearchableSpinner searchableSpinner = (SearchableSpinner) findViewById(R.id.searchable_spinner);
String[] names = new String[]{"India","CHINA","UK","US","MALYSIA"};
ArrayAdapter arrayAdapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_spinner_dropdown_item,names);
searchableSpinner.setAdapter(arrayAdapter);
searchableSpinner.setTitle("Select Item");
searchableSpinner.setPositiveButton("OK");
}
Output
On click of the dropdown
What i have done?
//added the library in gradle
compile 'com.toptoche.searchablespinner:searchablespinnerlibrary:1.3.1'
//new_form_layout (i have created this)
<com.toptoche.searchablespinnerlibrary.SearchableSpinner
android:id="#+id/smart_msn_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="right|center_vertical"
android:gravity="right" />
**In My Fragment**
#BindView(R.id.smart_msn_spinner)
SearchableSpinner smartMsnSpinner;
Now I have created a bindListners() function in which I am binding all the values and I am calling it in my onCreateView function
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.new_form_layout, container, false);
ButterKnife.bind(this, view);
bindListners(); // here i am calling it
imsiNo.setVisibility(View.GONE);
setupUI(mScrollView);
}
Bundle arguments = getArguments();
if (arguments != null && arguments.containsKey("install_id")) {
isNewInstall = false;
editInstallId = arguments.getString("install_id");
getActivity().setTitle(getString(R.string.title_fragment_edit_form));
setEditData();
imsiNo.setVisibility(View.GONE);
resetFormButton.setVisibility(View.GONE);
} else {
getActivity().setTitle(getString(R.string.title_fragment_new_form));
}
/*mCoordinatesReceiver = new CoordinatesReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Common.GetCoordinatesAction());
getActivity().registerReceiver(mCoordinatesReceiver, intentFilter);*/
return view;
}
bindListeners(){
.......
//Searchable smartMsnSpinner spinner and adapter
meterSrArrayList = new ArrayList<String>();
meterSrNumAdapter = new ArrayAdapter<String>(getActivity(), R.layout.custom_spinner_layout, meterSrArrayList);
smartMsnSpinner.setAdapter(meterSrNumAdapter);
smartMsnSpinner.setTitle("Select Item");
smartMsnSpinner.setPositiveButton("Ok");
smartMsnSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedMeterNo = meterSrArrayList.get(position);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
On running my app i am just getting simple drop down list as before.
I don't know what is the problem and what I am missing as i have done everything that is in the sample.
I have run the sample code in my device and it's working fine. I don't know why it's not working on my app
Update
After watching the logcatthe error i am seeing is
Parcelable encountered IOException writing serializable object (name = com.toptoche.searchablespinnerlibrary.SearchableSpinner)
Any help would be highly appreciated.
I'm using same library but I didn't have this problem.
Anyway I had others problem both on visualization, Parcelization and Re-Initializing the same view (the scroll down view) with this library.
Personally I extended the "SearchableSpinner" and made this changes:
public class BaseSearchableSpinner extends SearchableSpinner
implements SearchView.OnAttachStateChangeListener {
private static final String TAG = BaseSearchableSpinner.class.getSimpleName();
private static final String TAG_DIALOG = TAG.concat(".dialog");
// Dialogs Tags
private static final String TAG_DIALOG_SEARCHABLE_LIST = TAG_DIALOG.concat(".searchableList");
// SearchableSpinner Fields
private static final String FIELD_SEARCHABLE_LIST_DIALOG = "_searchableListDialog";
private static final String FIELD_SEARCH_VIEW = "_searchView";
private static final String FIELD_SEARCHABLE_ITEM = "_searchableItem";
private static final String FIELD_ARRAY_ADAPTER = "_arrayAdapter";
private static final String FIELD_ITEMS = "_items";
private boolean mIsListDialogAdded;
private boolean mIsListenerAdded;
public BaseSearchableSpinner(Context context) {
super(context);
initListDialog();
}
public BaseSearchableSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
initListDialog();
}
public BaseSearchableSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initListDialog();
}
/** Override SearchableSpinner Methods **/
#Override
public boolean onTouch(View v, MotionEvent event) {
try{
SearchableListDialog sld = (SearchableListDialog) FieldUtils.readField(this, FIELD_SEARCHABLE_LIST_DIALOG, true);
ArrayAdapter adapter = (ArrayAdapter) FieldUtils.readField(this, FIELD_ARRAY_ADAPTER, true);
List items = (List) FieldUtils.readField(this, FIELD_ITEMS, true);
if (sld != null && adapter != null && items != null && event.getAction() == MotionEvent.ACTION_UP && checkIfListDialogNotAdded()) {
if(mIsListenerAdded){
mIsListDialogAdded = true;
}
items.clear();
for (int i = 0x0; i < adapter.getCount(); i++) {
items.add(adapter.getItem(i));
}
sld.show(scanForActivity(getContext()).getFragmentManager(), TAG_DIALOG_SEARCHABLE_LIST);
}
} catch (IllegalAccessException iaE){
EMaxLogger.onException(TAG, iaE);
}
return true;
}
/** Override SearchView.OnAttachStateChangeListener Methods **/
#Override
public void onViewAttachedToWindow(View view) {
mIsListDialogAdded = true;
}
#Override
public void onViewDetachedFromWindow(View view) {
mIsListDialogAdded = false;
}
/** Private Methods **/
private void initListDialog(){
try{
SearchableListDialog oldD = (SearchableListDialog) FieldUtils.readField(this, FIELD_SEARCHABLE_LIST_DIALOG, true);
if(oldD != null) {
BaseSearchableListDialog newD = new BaseSearchableListDialog(this);
newD.setArguments(oldD.getArguments());
newD.setOnSearchableItemClickListener(this);
FieldUtils.writeField(this, FIELD_SEARCHABLE_LIST_DIALOG, newD, true);
}
} catch (IllegalAccessException iaE){
EMaxLogger.onException(TAG, iaE);
}
}
private void initListenerOnCloseSearchView(SearchableListDialog instance) {
try{
SearchView sv = (SearchView) FieldUtils.readField(instance, FIELD_SEARCH_VIEW, true);
if(sv != null){
sv.addOnAttachStateChangeListener(this);
mIsListenerAdded = true;
}
} catch (IllegalAccessException iaE){
EMaxLogger.onException(TAG, iaE);
}
}
private boolean checkIfListDialogNotAdded(){
return !mIsListDialogAdded && scanForActivity(getContext()).getFragmentManager().findFragmentByTag(TAG_DIALOG_SEARCHABLE_LIST) == null;
}
private Activity scanForActivity(Context cont) {
if (cont == null)
return null;
else if (cont instanceof Activity)
return (Activity) cont;
else if (cont instanceof ContextWrapper)
return scanForActivity(((ContextWrapper) cont).getBaseContext());
return null;
}
/** Private Classes **/
#SuppressLint("ValidFragment")
public static class BaseSearchableListDialog extends SearchableListDialog {
private BaseSearchableSpinner mOuter;
private BaseSearchableListDialog(BaseSearchableSpinner bss){
super();
mOuter = bss;
}
/** Override SearchableListDialog Methods **/
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog dialog = (AlertDialog) super.onCreateDialog(savedInstanceState);
mOuter.initListenerOnCloseSearchView(this);
return dialog;
}
}
}
Try using this and see if it works.
Also I changed the adapter to have custom texts and don't always display the "toString" of an object :/ I normally use the toString only for debugging purposes, so to show info about an object I make specific methods.
So this is the class for the Adapter:
public abstract class BaseSearchableSpinnerAdapter<T> extends ArrayAdapter<CharSequence> {
// Empty Item Label
protected static final String LABEL_EMPTY_ITEM = " ";
// Label Length
protected static final int LABEL_LENGTH = 50;
// Spinner Adapter Positions
public static final int POS_ITEM_NOT_FOUND = -0x1;
public static final int POS_EMPTY_ITEM = 0x0; // Not always true, depends if implemented
protected List<T> mItems;
private int mResLayout;
public BaseSearchableSpinnerAdapter(#NonNull Context context, #LayoutRes int resource) {
super(context, resource);
mItems = new ArrayList<>();
mResLayout = resource;
}
/** Abstract Methods **/
public abstract <T extends CharSequence> T getLabelView(int pos);
/** Override ArrayAdapter Methods **/
#NonNull
#Override
public View getView(int position, View convertView, #NonNull ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(mResLayout, parent, false);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.spinner_default, parent, false);
}
}
TextView tv = convertView.findViewById(R.id.text1);
if(tv != null){
tv.setText(getLabelView(position));
}
return convertView;
}
#Override
public void clear(){
mItems.clear();
super.clear();
}
/** Public Methods **/
public void addAll(List<T> objs){
clear();
ArrayList<CharSequence> labels = new ArrayList<>();
if(objs != null && objs.size() > 0x0){
mItems.addAll(objs);
for(int i = 0x0; i < objs.size(); i++){
labels.add(getLabelView(i));
}
}
super.addAll(labels);
}
public T getMyItem(int pos){
if(mItems != null && mItems.size() > pos && pos != -0x1){
return mItems.get(pos);
}
return null;
}
public List<T> getMyItems(){
return mItems;
}
}
Extend this class and use the object you want.
LABEL_EMTPY_ITEM is a long series of spaces because in some app when the text don't take all the line in the list view it will be clickable only on the text and not on all the line.. So when you have no item the clikable part of the line is a little small piece on the left (in my case, I had this problem).
Example to extend this base Adapter class:
public class MyObjectSearchableSpinnerAdapter extends BaseSearchableSpinnerAdapter<MyObject> {
private #StringRes int mIdFstr;
public MyObjectSearchableSpinnerAdapter(#NonNull Context context, #LayoutRes int resource){
this(context, resource, R.string.fstr_two_fields_dash);
}
public MyObjectSearchableSpinnerAdapter(#NonNull Context context, #LayoutRes int resource, int idFstr){
super(context, resource);
mIdFstr = idFstr;
}
/** Override BaseSearchableSpinnerAdapter Methods **/
#Override
public <T extends CharSequence> T getLabelView(int pos) {
MyObject item = mItems.get(pos);
if(item != null){
return (T) (!TextUtils.isEmpty(item.getName2()) ?
getContext().getString(mIdFstr, item.getName1(), item.getName2()) :
item.getName1());
}
return (T) LABEL_EMPTY_ITEM;
}
/** Public Methods **/
public int getItemPosition(int idMyObject){
return getItemPosition(String.valueOf(idMyObject));
}
public int getItemPosition(String idMyObject){
if(mItems != null && mItems.size() > 0x0){
for(int i = 0x0; i < mItems.size(); i++){
MyObject item = mItems.get(i);
if(item != null && idMyObject.equals(item.getId())){
return i;
}
}
}
return POS_ITEM_NOT_FOUND;
}
}
Example Init BaseSearchableSpinner:
private void initBaseSearchableSpinnerMyObjects(){
MyObjectSearchableSpinnerAdapter adapter = new MyObjectSearchableSpinnerAdapter(getContext(), R.layout.spinner_default);
adapter.setDropDownViewResource(R.layout.spinner_default);
mBaseSearchableSpinnerMyObjects.setAdapter(adapter);
}
Example Add your list of MyObject to the adapter:
((MyObjectSearchableSpinnerAdapter)mBaseSearchableSpinnerMyObjects.getAdapter()).addAll(items);
Example Get back an object from a BaseSearchableSpinner with an extensions of BaseSearchableAdapter with a list of MyObject :
MyObject obj = ((MyObjectSearchableSpinnerAdapter) mBaseSearchableSpinnerMyObjects.getAdapter()).getMyItem(mBaseSearchableSpinnerMyObjects.getSelectedItemPosition());
Have a nice coding and day!
bb

Android two way data binding for custom component?

I'm trying to follow this blog post to try and get two way data binding to work for a custom component (A constraint view with an EditText in it).
I'm able to get two standard EditText components to be in sync (both ways) with my model, but I'm having trouble getting the changes in my custom component to flow into my model (although one way data binding works).
My model:
public class Model extends BaseObservable {
private String value;
#Bindable
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
notifyPropertyChanged(company.com.databinding.BR.value);
}
public Model() {
value = "Value";
}
}
Activity:
#InverseBindingMethods({
#InverseBindingMethod(
type = CustomComponent.class,
attribute = "value",
method = "getValue")
})
public class MainActivity extends AppCompatActivity {
#BindingAdapter("value")
public static void setColor(CustomComponent view, String value) {
if (!value.equals(view.getValue())) {
view.setValue(value);
}
}
#BindingAdapter(
value = {"onValueChange", "valueAttrChanged"},
requireAll = false
)
public static void setListeners(CustomComponent view,
final ValueChangeListener onValueChangeListener,
final InverseBindingListener inverseBindingListener) {
ValueChangeListener newListener;
if (inverseBindingListener == null) {
newListener = onValueChangeListener;
} else {
newListener = new ValueChangeListener() {
#Override
public void onValueChange(CustomComponent view,
String value) {
if (onValueChangeListener != null) {
onValueChangeListener.onValueChange(view,
value);
}
inverseBindingListener.onChange();
}
};
}
ValueChangeListener oldListener =
ListenerUtil.trackListener(view, newListener,
R.id.textWatcher);
if (oldListener != null) {
view.removeListener(oldListener);
}
if (newListener != null) {
view.addListener(newListener);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setModel(new Model());
}
}
Custom component:
public class CustomComponent extends ConstraintLayout {
private String value;
private EditText txt;
private TextWatcher textWatcher;
ValueChangeListener listener;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
if (txt != null) {
txt.setText(value);
}
}
public CustomComponent(Context context) {
super(context);
init(context);
}
public CustomComponent(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CustomComponent(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context) {
}
private void init(Context context, AttributeSet attrs) {
View.inflate(context, R.layout.custom_component, this);
txt = findViewById(R.id.txt_box);
final CustomComponent self = this;
textWatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if (listener != null) {
listener.onValueChange(self, editable.toString());
}
}
};
txt.addTextChangedListener(textWatcher);
}
public void addListener(ValueChangeListener listener) {
this.listener = listener;
}
public void removeListener(ValueChangeListener listener) {
this.listener = null;
}
}
public interface ValueChangeListener {
public void onValueChange(CustomComponent view, String value);
}
I think the section "Hooking The Event" in that post has gone completely over my head; I really only needed a simple setter and getter for the component, and so couldn't quite understand what was being done in that BindingAdapter. Of all of them I think it's this line that I don't get at all:
ValueChangeListener oldListener =
ListenerUtil.trackListener(view, newListener,
R.id.textWatcher);
Demo at: https://github.com/indgov/data_binding
Sorry that the ListenerUtil was confusing. That's only useful when your component supports multiple listeners. In that case, you can't just set a new listener, you must remove the old one and add the new one. ListenerUtil helps you track the old listener so it can be removed. In your case, it can be simplified:
#BindingAdapter(
value = {"onValueChange", "valueAttrChanged"},
requireAll = false
)
public static void setListeners(CustomComponent view,
final ValueChangeListener onValueChangeListener,
final InverseBindingListener inverseBindingListener) {
ValueChangeListener newListener;
if (inverseBindingListener == null) {
newListener = onValueChangeListener;
} else {
newListener = new ValueChangeListener() {
#Override
public void onValueChange(CustomComponent view,
String value) {
if (onValueChangeListener != null) {
onValueChangeListener.onValueChange(view,
value);
}
inverseBindingListener.onChange();
}
};
}
view.setListener(newListener);
}
and then replace addListener() with setListener() and you don't need the removeListener() because you can always set the listener to null.
The problem you're seeing is in your component:
public String getValue() {
return value;
}
You're returning the value that was last set by the setter and not the value that is in the EditText. To solve this:
public String getValue() {
return txt.getText().toString();
}

How to create a custom view that is initialize only once and common for all activity in Android?

I am trying to create a custom view in android. With following condition :
The view should be initialize only once
The same view should be used throughout application
I have tried to initialize the view from application class and adding to the current activity.
Following is the code :
ViewInAppApplcation
public class ViewInAppApplcation extends Application {
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new AppActivityCallBack());
}
private class AppActivityCallBack implements ActivityLifecycleCallbacks {
StatusBarView statusBarView = null;
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
final Activity activity1 = activity;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (statusBarView == null) {
statusBarView = new StatusBarView(activity1);
}
}
});
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
LinearLayout view = (LinearLayout) activity.findViewById(R.id.status_bar_view_holder);
if (view != null) {
view.addView(statusBarView, 0);
}
}
#Override
public void onActivityPaused(Activity activity) {
LinearLayout view = (LinearLayout) activity.findViewById(R.id.status_bar_view_holder);
if (view != null) {
view.removeView(statusBarView);
}
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
}
StatusBarView
public class StatusBarView extends RelativeLayout{
/**Activity context object.*/
private Context context = null;
/** View object */
private StatusBarView statusBarView = null;
/**
* Constructor
*
* #param context - Context Reference
*
*/
public StatusBarView(Context context) {
super(context);
this.context = context;
this.statusBarView = this;
initView();
}
/**
* Constructor
*
* #param context - Context Reference
* #param attrs - Set of attributes
*/
public StatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.statusBarView = this;
initView();
}
/**
* Constructor
*
* #param context - Context Reference
* #param attrs - Attribute List
* #param defStyleAttr - Default Style Attributes
*/
public StatusBarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
this.statusBarView = this;
initView();
}
/**
* Inflate the app status bar xml and add to view
*/
private void initView() {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.view_app_status_bar, this, false);
new Asy().execute();
statusBarView.addView(view);
}
public void setValue(String value) {
TextView textView = (TextView) findViewById(R.id.txt_status);
textView.setText(value);
}
private class Asy extends AsyncTask<Void,Integer,String>
{
#Override
protected String doInBackground(Void... params) {
for (int i=0;i<20;i++)
{
publishProgress(i);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "DONE";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
setValue(values[0]+"");
}
}
}
MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.next).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, Main2Activity.class);
startActivity(intent);
}
});
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:orientation="vertical">
<LinearLayout
android:background="#color/colorAccent"
android:id="#+id/status_bar_view_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<Button
android:id="#+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
This code will add a statusbar view to current activity. Is there any other way to do it?

roboguice inject in customer

I have a widget View as below:
public class RemoteNumView extends FrameLayout {
how call I use Roboguice just as in RoboActivity? As below:
#InjectView(R.id.btn_remote_control_num_0)
private TextView mText;
Full code is:
/**
* Created by bbcv on 13-12-12.
*/
public class RemoteNumView extends FrameLayout {
private IService mService;
#InjectView(R.id.btn_remote_control_num_0)
private TextView mText;
public RemoteNumView(Context context) {
super(context);
///
addView(LayoutInflater.from(context).inflate(R.layout.v_remote_control_fun,null));
}
public RemoteNumView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RemoteNumView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setService(IService service){
mService = service;
}
}
Anyone can HELP?
Solved it by writing custom code. Roboguice is badly written for this purpose.
protected void injectViews() {
for (Field field : this.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(InjectView.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new UnsupportedOperationException("Views can't be staticaly assigned.");
} else {
if (View.class.isAssignableFrom(field.getType())) {
try {
final InjectView injectView = field.getAnnotation(InjectView.class);
;
final int id = injectView.value();
View view = findViewById(id);
if ((view == null) && Nullable.notNullable(field)) {
throw new NullPointerException(String.format("Can't inject null value into %s.%s when field is not #Nullable", field.getDeclaringClass(), field.getName()));
}
field.setAccessible(true);
field.set(this, view);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
} else {
throw new UnsupportedOperationException("Need view type to assign");
}
}
}
}

Update in real time GraphicalView of AChartEngine

I want to have an app that shows me a textview and a line chart dynamically updated with the values that I receive from a range sensor.
I used a modified TextView which manages the messages and it works well.
I tried to do the same thing with a GraphicalView from AChartEngine, but the Chart doesn't change with the arrival of new messages.
Here is my code, any suggestion or advice?
public class NxtActivity extends RosActivity{
private XYSeries mCurrentSeries = new XYSeries("range data series");
private XYSeriesRenderer mCurrentRenderer = new XYSeriesRenderer();
private XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
private XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
private LineChart linec;
private Canvas canvas = new Canvas();
private RosChartView<std_msgs.String> rdrawview;
private RosTextView<std_msgs.String> rosTextView;
private Android_Talker talker;
private java.net.URI master_uri;
//costruttore
public NxtActivity() {
// The RosActivity constructor configures the notification title and ticker
// messages.
super("Pubsub Tutorial mod", "Pubsub Tutorial mod");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nxt);
//setto i parametri del renederer relativo alla singola seria
mCurrentRenderer.setPointStyle(PointStyle.CIRCLE);
mCurrentRenderer.setFillPoints(true);
mCurrentRenderer.setLineWidth(2);
//setto i parametri del renderer globale
mRenderer.addSeriesRenderer(mCurrentRenderer);
mRenderer.setApplyBackgroundColor(true);
mRenderer.setBackgroundColor(Color.argb(100, 50, 50, 50));
mRenderer.setAxisTitleTextSize(16);
mRenderer.setChartTitleTextSize(20);
mRenderer.setLabelsTextSize(15);
mRenderer.setLegendTextSize(15);
mRenderer.setMargins(new int[] { 20, 30, 15, 0 });
mRenderer.setZoomButtonsVisible(true);
mRenderer.setPointSize(10);
mRenderer.setXTitle("time");
mRenderer.setYTitle("ranges");
//setto la serie
mCurrentSeries.add(1,1);
//setto il dataset
mDataset.addSeries(mCurrentSeries);
//setto LineChart
linec = new LineChart(mDataset,mRenderer);
//inizializzo RosChartView
rdrawview=new RosChartView<std_msgs.String>(this,linec,canvas);
rdrawview.setTopicName("chatter_nxt");
rdrawview.setMessageType(std_msgs.String._TYPE);
rdrawview.setMessageToStringCallable(new MessageCallable<String, std_msgs.String>() {
#Override
public String call(std_msgs.String message) {
return message.getData();
}
});
//assegno RosChartView al Layout corrispondente
LinearLayout layout = (LinearLayout) findViewById(R.id.chart);
layout.addView(rdrawview, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
rdrawview.repaint();
//rdrawview.setup(3,3);
rosTextView = (RosTextView<std_msgs.String>) findViewById(R.id.text1);
rosTextView.setTopicName("chatter_nxt");
rosTextView.setMessageType(std_msgs.String._TYPE);
rosTextView.setMessageToStringCallable(new MessageCallable<String, std_msgs.String>() {
#Override
public String call(std_msgs.String message) {
return message.getData();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_nxt, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
//case android.R.id.home:
// NavUtils.navigateUpFromSameTask(this);
// return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void init(NodeMainExecutor nodeMainExecutor) {
talker = new Android_Talker();
NodeConfiguration nodeConfiguration = NodeConfiguration.newPrivate();
// At this point, the user has already been prompted to either enter the URI
// of a master to use or to start a master locally.
try {
master_uri = new java.net.URI("http://150.145.11.98:11311");
nodeConfiguration.setMasterUri(master_uri);
}
catch(URISyntaxException e){
System.out.println("URI is a malformed URL");
}
rdrawview.setup(3,3);
nodeConfiguration.setMasterUri(master_uri);
nodeMainExecutor.execute(talker, nodeConfiguration);
// The RosTextView is also a NodeMain that must be executed in order to
// start displaying incoming messages.
nodeMainExecutor.execute(rosTextView, nodeConfiguration);
nodeMainExecutor.execute(rdrawview, nodeConfiguration);
}
}
Modified textview:
public class RosTextView<T> extends TextView implements NodeMain {
private String topicName;
private String messageType;
private int count=0;
private MessageCallable<String, T> callable;
public RosTextView(Context context) {
super(context);
}
public RosTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RosTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setTopicName(String topicName) {
this.topicName = topicName;
}
public void setMessageType(String messageType) {
this.messageType = messageType;
}
public void setMessageToStringCallable(MessageCallable<String, T> callable) {
this.callable = callable;
}
#Override
public GraphName getDefaultNodeName() {
return GraphName.of("android_gingerbread/ros_text_view");
}
#Override
public void onStart(ConnectedNode connectedNode) {
Subscriber<T> subscriber = connectedNode.newSubscriber(topicName, messageType);
subscriber.addMessageListener(new MessageListener<T>() {
#Override
public void onNewMessage(final T message) {
if (callable != null) {
post(new Runnable() {
#Override
public void run() {
setText(callable.call(message));
count++;
if((count%2)==0){setTextColor(Color.RED);}
else{setTextColor(Color.BLUE);}
}
});
} else {
post(new Runnable() {
#Override
public void run() {
setText(message.toString());
}
});
}
postInvalidate();
}
});
}
#Override
public void onShutdown(Node node) {
}
#Override
public void onShutdownComplete(Node node) {
}
#Override
public void onError(Node node, Throwable throwable) {
}
}
Modifed graphicalview:
public class RosChartView<T> extends GraphicalView implements NodeMain {
//---------
private XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
private XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
private XYSeries mCurrentSeries = new XYSeries("range data series");
private int x;
private int y;
Context context;
Canvas canvas;
//---------
private String topicName;
private String messageType;
private int count=0;
private MessageCallable<String, T> callable;
public RosChartView(Context context, LineChart xyc, Canvas canvas_) {
super(context,xyc);
this.context=context;
mDataset = xyc.getDataset();
mRenderer = xyc.getRenderer();
mRenderer.setClickEnabled(true);
mRenderer.setSelectableBuffer(100);
x=0;
y=0;
canvas=canvas_;
}
public RosChartView(Context context, AttributeSet attrs, LineChart xyc) {
super(context, xyc);
mDataset = xyc.getDataset();
mRenderer = xyc.getRenderer();
mRenderer.setClickEnabled(true);
mRenderer.setSelectableBuffer(100);
x=0;
y=0;
}
public RosChartView(Context context, AttributeSet attrs, int defStyle, LineChart xyc) {
super(context, xyc);
mDataset = xyc.getDataset();
mRenderer = xyc.getRenderer();
mRenderer.setClickEnabled(true);
mRenderer.setSelectableBuffer(100);
x=0;
y=0;
}
public void setTopicName(String topicName) {
this.topicName = topicName;
}
public void setMessageType(String messageType) {
this.messageType = messageType;
}
public void setMessageToStringCallable(MessageCallable<String, T> callable) {
this.callable = callable;
}
#Override
public GraphName getDefaultNodeName() {
return GraphName.of("android_gingerbread/ros_text_view");
}
#Override
public void onStart(ConnectedNode connectedNode) {
Subscriber<T> subscriber = connectedNode.newSubscriber(topicName, messageType);
subscriber.addMessageListener(new MessageListener<T>() {
#Override
public void onNewMessage(final T message) {
if (callable != null) {
post(new Runnable() {
#Override
public void run() {
count++;
x=count;
y=Integer.parseInt(callable.call(message));
XYSeries series=new XYSeries("new_series");
series=mCurrentSeries;
series.add(2,2);
mDataset.removeSeries(mCurrentSeries);
mCurrentSeries=series;
mDataset.addSeries(mCurrentSeries);
repaint();
}
});
} else {
post(new Runnable() {
#Override
public void run() {
count++;
x=count;
y=Integer.parseInt(message.toString());
mCurrentSeries.add(x,y);
}
});
}
postInvalidate();
}
});
}
#Override
public void onShutdown(Node node) {
}
#Override
public void onShutdownComplete(Node node) {
}
#Override
public void onError(Node node, Throwable throwable) {
}
public void setup(double x,double y)
{
mCurrentSeries.add(x,y);
this.repaint();
}
}
layout
<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" >
<org.ros.android.view.RosTextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dip"
/>
<LinearLayout
android:id="#+id/chart"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_below="#id/text1"
android:orientation="horizontal" />
</RelativeLayout>
When a message is received, you do the following:
XYSeries series=new XYSeries("new_series");
series=mCurrentSeries;
series.add(2,2);
mDataset.removeSeries(mCurrentSeries);
mCurrentSeries=series;
mDataset.addSeries(mCurrentSeries);
This means that you create a new series, then the reference to the current series is given to the variable that was previously created as new series then you add a point at location 2, 2 then you remove the series and add it back. This is totally wrong.
The following should be sufficient:
mCurrentSeries.add(x, y); // NOT 2, 2

Categories

Resources