Butterknife - multiple injections - android

I have an Activity as a target for Butterknife and I want to use the same Activity as a target for another View I am inflating in runtime. Is there a way to do it?
This is what I've tried and it doesn't work:
#InjectView(R.id.main)
TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
ButterKnife.inject(this);
createDialog();
}
void createDialog() {
View v = View.inflate(...); // v has a view inside with id R.id.tv
ButterKnife.inject(this, v);
new Dialog(this).setView(v)....show();
}
#OnClick(R.id.tv)
void click() {
// ...
}

You can't inject into the same object twice. Use two different
objects. One can be the activity but one needs to be something else.
It can be anything, just a simple object which holds all the fields
for the dialog, for example.
There's simply no way to inject into the same object twice.
Issue comment by Jake Wharton

Related

Databinding apply for one layout used by multiple activity/fragment

I am replacing existing code by databinding. But I face a problem.
I have some layout files shared by more than one activity/fragment. E.g there is a layout file layout_sub used by SubFragmentA and its extending class SubFragmentB. And the data model used in these two fragment are not the same.
The code looks like following.
public class SubFragmentA extends Fragment {
private DataA dataA;
#Override
public View onCreateView(Bundle Bundle) {
View v = LayoutInflator.from(getActivity()).inflate(R.layout.shared_layout);
initView(v, dataA);
return v;
}
private void initView(view v, DataA dataA) {
// use dataA to init v
}
}
public class SubFragmentB extends Fragment {
private DataB dataB;
#Override
public View onCreateView(Bundle Bundle) {
View v = LayoutInflator.from(getActivity()).inflate(R.layout.shared_layout);
initView(v, dataB);
return v;
}
private void initView(view v, DataB dataB) {
// use dataB to init v
}
}
So far, I think using DataA and DataB in layout_sub file at the same time is not a good idea, because it would require a lot of redundant code to decide which object to be used.
Please share your ideas on this problem.
Finally, I got a solution. The databinding is used for MVVM pattern. That means one layout corresponds to one ViewModel. And the ViewModel contains every data for UI layout. So I should prepare one ViewModel for each layout file. And every fragment/activity should just handle the ViewModel.

Android Fragment and logical application design

This is more of a design question and how one would go about designing applications. I have been having fun with fragments, but one thing that doesn't make sense to me something like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 2);
Button btnOne = (Button) getView().findViewById(R.id.one);
btnOne.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
String currentText = getScreen().getText().toString();
currentText += "1";
getScreen().setText(currentText);
}
});
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.standard_calculator, container, false);
return view;
}
/** Return the screen TextView object for manipulation
* #return screen
*/
public TextView getScreen() {
return screen;
}
Screen title are private variables in the class and this isn't the whole class, but just the part that I need to help my question. There are going to be at least 15 or so buttons that manipulate the screen and it doesn't feel like good practice to and put them all in the onCreate method, I was wondering whether it would be better design to have them in another class that let the methods in the fragment be more specific to the life-cycle of the fragment, although one can say that the buttons are used by the fragment and therefore should be part of the class. Perhaps an "initialising" method is needed.
I was hoping someone might be able to direct me to some design patterns or logical way of thinking about application design, it is quite different.
Many thanks.
Putting them in the XML is less versatile than doing it in code. If you don't want to have XXX anonymous methods, you can make your own Fragment/Class implement View.onClickListener and implement the onClick method:
#Override
public void onClick(final View v) {
if ( v.getId() == R.id.btn_logout ){
// Do One Thing
} else if ( v.getId() == R.id.btn_about) {
// Do Something Else
} else if ( v.getId() == R.id.btn_shutdown) {
// Or Maybe do this :)
}
}
Then in your onViewCreated just assign each button with "this"
final someBtn = (Button) view.findViewById(R.id.btn_logout);
someBtn.setOnClickListener(this);
That can be cleaner looking than a bunch of anonymous methods and you know you have your click listeners in one place.
You don't have to initialize them all in the onCreate() method. In fact, you don't have to initialize them in java code at all. You could simply define them in xml and define an "onClick" property in your xml. The method that you set in "onClick" will be called for that button. It's one way to make your Activities cleaner.

Which lifecycle method will be invoked when Activity is showing?

Sometimes I need to do some operations(e.g. changing layout) when the activity is just showing. What I do now is using post():
public class MyActivity extends Activity {
#Override
public void onCreate() {
...
container.post(new Runnable(){
resize(container);
});
}
}
Is there any lifecycle method like onCreate can be used to simplify the code, that I don't need to call post?
#Override
public void onX() {
resize(container);
}
I think you mean do something after the UI is displayed.
Using a global layout listener has always worked well for me. It has the advantage of being able to remeasure things if the layout is changed, e.g. if something is set to View.GONE or child views are added/removed.
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// inflate your main layout here (use RelativeLayout or whatever your root ViewGroup type is
LinearLayout mainLayout = (LinearLayout ) this.getLayoutInflater().inflate(R.layout.main, null);
// set a global layout listener which will be called when the layout pass is completed and the view is drawn
mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
// at this point, the UI is fully displayed
}
}
);
setContentView(mainLayout);
http://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener.html

OnTouchListener on Activity never calls

I used this code, but when i click on activity at runtime, it never hits in OnTouch() method. Can someone guide me what i am doing wrong? Should i need to setcontentview of this activity? Actually i want the coordinates of activity where user touch during execution.
public class TouchTestAppActivity extends Activity implements OnTouchListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.touch);
}
#Override
public boolean onTouch(View arg0, MotionEvent arg1)
{
// TODO Auto-generated method stub
String test = "hello";
}
}
UPDATE:
You need to do this :
In your XML layout file, you need an ID for the root view: android:id="#+id/myView"
In youer onCreate() method, write this:
LinearView v= (LinearView) findViewById(R.id.myView);
v.setOnTouchListener(this);
Assuming that your root view is a LinearView
You should the onTouchListener to relevant GUI components.
For example:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.touch);
TextView someView = (TextView)findViewById(R.id.some_view_from_layout_xml);
someView.setOnTouchListener(this); // "this" is the activity which is also OnTouchListener
}
You have to add a the listener using setOnTouchListener() otherwise who will give call to your onTouch method. any listener works on any view. so you have to add the listener to the view eg button.setOnTouchListener(this);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View vi = inflater.inflate(R.layout.yourxml, null);
setCOntentView(vi);
vi.setOnTouchListener(this);
In onCreate, you need to set the content view (just uncommenting the second line should probably work) and then you need to set your OnTouchListener (your activity) as the onTouchListener for a view in your application.
Let's say you've got a view in your layout called "MainView"; it would look something like this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View view = findViewById(R.id.MainView);
view.setOnTouchListener(this);
}
This article has a good example:
http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-2-building-the-touch-example/1763

creating a xml layout from a custom layout. is it possible?

MainActivity.java:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setTitle(R.string.app_name);
setContentView(new SampleView(this));
}
}
SampleView.java:
public class SampleView extends View {
#Override
protected void onDraw(Canvas canvas) {
if (certaincondition = true) {
//add elements to canvas etc
} else {
//How do I do the below? The layout is defined in xml.
//I do not want to use Intent. Please help me
//create a layout from resource R.layout.idAbout and transfer control.
}
}
}
Use a layout inflater:
View newRootViewElement;
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
newRootViewElement= li.inflate(R.layout.idAbout, null);
You can inflate a layout using
View.inflate(getContext(), R.layout.idAbout, viewParent);
where viewParent is a ViewParent that will be the parent of the inflated view (and can be null).
But what are you trying to do? It's more than a little odd to start a new activity or to modify the view hierarchy from within onDraw(). You might want to post a runnable to a Handler that will do what you want on the next cycle of the event loop. To start a new activity (such as displaying “About” info for the app) you should take a look at the Intent class.

Categories

Resources