Android-podział klas

0

Witam.
Zaczynam sie uczyć pisać na androida i mam takie pytanie jak powinno dzielić sie klasy pisząc pod androida? Co znaczy że nie powinno łączyć sie UI i logiki? (co to znaczy rozumiem tylko jak to stosować)

Napisałem prosty kalkulator BMI

package pl.danek.BMIcalculator;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

	private EditText weightEditText;
	private EditText growthEditText;
	private TextView resultTextView;
	private Button calculateButton;
	
	public static final String startOfResult="Your bmi is: ";
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		createComponents();
		
		
	}

	private void createComponents() {
		weightEditText=(EditText)findViewById(R.id.weight);
		growthEditText=(EditText)findViewById(R.id.growth);
		resultTextView=(TextView)findViewById(R.id.result);
		resultTextView.setText(startOfResult);
		calculateButton=(Button)findViewById(R.id.calculate);
		calculateButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				calculate();
			}
		});
	}
	
	
	private void calculate() {
		double weight=Double.parseDouble(weightEditText.getText().toString());
		double growth=Double.parseDouble(growthEditText.getText().toString());
		double bmi=weight/Math.pow(growth, 2);
		BMI temp = BMI.getBMIStan(bmi);
		String result=bmi+"";
		result=result.substring(0, 4);
		resultTextView.setText(startOfResult+result+" ("+temp.toString()+")");
	}

	
}
package pl.danek.BMIcalculator;


public enum BMI {

	UNKNOWN(Double.MAX_VALUE, -1, "Unknown"),
	UNDERWEIGHT(0, 19, "Underweight"),
	NORMAL(20, 26, "Normal"),
	OVERWEIGHT(26, 31, "Overweight"),
	OBESE(31, 44, "Obese"),
	DEAD(45, Double.MAX_VALUE, "Probably already dead");
	
	
	private final double min;
	private final double max;
	private final String info;
	
	private BMI( double min,double max,String info) {
		this.max = max;
		this.min = min;
		this.info = info;
	}

	@Override
	public String toString(){
		return info;
	}

	public static BMI getBMIStan(double bmiIndex){
		for (BMI bmi : BMI.values()) {
			if(bmi.isInRange(bmiIndex)){
				return bmi;
			}
		}
		return UNKNOWN;
	}
	
	private boolean isInRange(double bmiIndex){
		return min<bmiIndex && bmiIndex<max;
	}
	
}

I jak zastosować sie do tego zeby nie łączyć logiki z UI? Wystawić metode calculate jako osobny obiekt?

1

Budując ui przy pomocy xml oddzielasz sobie widok z automatu - więc Twój problem nie istnieje.
Btw: nie wygodniej i ładniej przypisać akcje do buttona w ten sposób:

<Button
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
     android:text="@string/self_destruct"
     android:onClick="selfDestruct" />

i akcja:

public void selfDestruct(View view) {
     //TODO
 }
0

Może wygodniej, ale jeśli używasz Fragmentów, to chyba nie możesz tak zrobić, bo zdaje się, że tam jest metoda Activity, w której jest przycisk, a nie Fragmentów.

0

metodę selfDestruct dodajesz w tym przypadku w mainActivity, jeżeli używasz fragmentów to dodajesz to jako metoda w klasie fragmentu która nadmuchała Twój layout.

0

Albo używasz butterknife/android annotations/roboguice. Wtedy bez względu na to czy jest to fragment czy aktywność można zrobić tak:


@InjectView(R.id.cos_tam) TextView text; 

@OnClick(R.id.moj_button)
protected void click() {
   //akcja dla buttona
}
1

Możesz zwiększyć czytelność kodu i lepiej go rozdzielić poprzez wstrzykiwanie zależności (Dependency Injection).
Przez długi czas wiele osób korzystało do tego celu z Roboguice'a, ale w tej bibliotece wstrzykiwanie zależności realizuje się przez refleksję, więc wszystkie zależności są tworzone w runtime i jeśli Twój projekt się rozrośnie i będzie miał bardzo wiele zależności, to będzie uruchamiał się bardzo wolno.
Ostatnio popularny jest wspomniany Dagger, który generuje klasy w javie ze wszystkimi zależnościami, więc nie trzeba ich za każdym razem tworzyć podczas uruchamiania aplikacji. Do interakcji z UI możesz użyć biblioteki Butter Knife. Wtedy możesz użyć annotacji i wywalić metodę createComponents().
Niestety (albo stety) domyślna architektura aplikacji w Androidzie jest bardzo luźna i nie wspiera wzorca MVC, a w wielu tutorialach wrzuca się wszystko do Activity. Najlepiej rozdziel kod tak, aby w activity było jak najmniej kodu. Np. zmienną startOfResult możesz wywalić, a ten tekst trzymać w res/values/strings.xml. Metodę calculate możesz przenieść do osobnej klasy i nazwać ją np. ActivityController, a potem wstrzykąć sobie tę klasę lub stworzyć obiekt w konstruktorze. Możesz też stworzyć interfejs i podpinać do niego różne obiekty, które go implementują (np. gdybyś miał wiele klas z metodą calculate). Do metody calculate możesz przekazać kontekst aplikacji i wywołać z activity tylko metodę, którą sobie stworzysz - np. onCalculated, gdzie będziesz tylko wyświetlał wartość w jakimś elemencie UI. Generalnie, najlepiej wywalić wszystkie metody, które nie są odpowiedzialne za wyświetlanie danych w UI do osobnych klas. Jak później znajdę chwilę, to ewentualnie podam tu jakiś konkretny przykład. ;)

Edit: Przygotowałem przykład. Jest to oczywiście tylko idea i trzeba to dostosować do konkretnego rozwiązania, ale mam nadzieję, że zrozumiesz, o co chodzi. ;)

Interfejs ActivityView (jest potrzebny po to, aby móc wywoływać nasze metody z klasy Activity z poziomu klasy kontrolera)

interface ActivityView {
   void onCalculated(int result);
}

kontroler - Klasa ActivityController

class ActivityController {
   private ActivityView activityView;

   public ActivityController(ActivityView activityView) {
      this.activityView = activityView;
   }

   public void calculate() {
      int result = 0;
      // tutaj wykonaj kalkulacje i zapisz je do zmiennej result
      activityView.onCalculated(result);
   }
}

Activity - klasa MyActivity

class MyActivity extends Activity implements ActivityView {

   @InjectView(R.id.myTextView)
   private TextView textView; // tutaj mamy przykład wstrzykiwania z RoboGuice, ale możesz też użyć innej libki
   private ActivityController controller;

   public void onCreate() {
      controller = new ActivityController(this);
   }

   @OnClick(R.id.calculateButton)
   public void calculate() {
      controller.calculate();
   }

   public void onCalculated(int result) {
      textView.setText(result);
   }

}

Dzięki takiemu podejściu mamy elegancko rozdzielony kod i realizujemy zasady: DI, SRP oraz ISP z SOLID-a. :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1