Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Single Activity Architecture

Avatar for Nevin Nevin
December 05, 2015

Single Activity Architecture

Avoid using fragment in android apps.
@jcconf 2015
https://github.com/cnevinc/noFragment
https://youtu.be/soQq4PWHzKc

Avatar for Nevin

Nevin

December 05, 2015
Tweet

More Decks by Nevin

Other Decks in Programming

Transcript

  1. Current 1. Multiple activities 2. One activity, multiple fragments 3.

    One activity, no fragment , multiple custom views 4. Sample app : https://github.com/cnevinc/noFragment
  2. Multiple Activities 1. Create new activity takes time 2. Hard

    to reuse the view Activity A Activity C Activity B Activity D
  3. Activity A Multiple fragments 1. Error-prone support library. 2. Complex

    life cycle in FragmentManager. 3. Nested fragment is only supported via code , can’t be inflated from xml. Fragment A Fragment C Fragment B Fragment D
  4. Multiple views Pros 1. Easy to reuse 2. No support

    lib or FragmentManager Cons 1. Knowledge about custom view lifecycle (2 methods) 2. Have to handle backpressed event manually ( 1 methods) 3. Have to handle in/out animation manually
  5. Custom View Lifecycle onFinishInflate 1. Setup / bind view @onFinishInflate

    2. Clean resource after @onDetachedFromWindow constructor onFinishInflate onAttachedToWindow onMeasured onLayout onDraw onDetachedFromWindow
  6. Custom View - xml <?xml version="1.0" encoding="utf-8"?>
 <com.nevinchen.nofragment.ui.InfoView android:id=“@+id/info_view" …

    >
 <RelativeLayout … >
 <android.support.v7.widget.CardView … >
 <RelativeLayout … >
 <ImageView android:id=“@+id/avatar" … /> 
 <TextView android:id=“@+id/name" … /> 
 <TextView android:id=“@+id/time” … />
 </RelativeLayout> </android.support.v7.widget.CardView>

  7. Custom View - Definition public class InfoView extends LinearLayout {

    
 @Bind(R.id.avatar)ImageView avatar;
 @Bind(R.id.name) TextView name; 
 @Override protected void onFinishInflate() {
 super.onFinishInflate();
 ButterKnife.bind(this);
 setupUI();
 } 
 @Override protected void onDetachedFromWindow() {
 super.onDetachedFromWindow();
 // clean up resource here
 }
 }
  8. Add View public static void AddMe(MainActivity host, User data) {


    InfoView v = (InfoView)host.getLayoutInflater().inflate(R.layout.info, nu ViewGroup parent =((ViewGroup)host.findViewById(android.R.id.content));
 bind(data); host.addContentView(v, p);
 } private void bind(User user) {
 this.user = user ;
 Picasso.with(getContext()).load(user.avatar).placeholder(R.drawable.ic_launcher).into(avatar name.setText(user.name);
 time.setText(user.time);
 
 }
  9. Setup Backpress private void setupBackPressed() {
 this.setFocusable(true);
 this.setFocusableInTouchMode(true);
 this.requestFocus();
 this.setOnKeyListener(new

    OnKeyListener() {
 public boolean onKey(View v, int keyCode,KeyEvent event){
 if (keyCode == KeyEvent.KEYCODE_BACK) {
 removeFromParent();
 }
 return true;
 }
 }); }
  10. Remove View public void removeFromParent() {
 ViewGroup parent = (ViewGroup)

    getParent(); parent.removeView(InfoView.this);
 } 

  11. Animation public void removeFromParent() {
 ViewGroup parent = (ViewGroup) getParent();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
 TransitionManager.beginDelayedTransition(parent); parent.removeView(v, p);
 }
  12. Animation public void removeFromParent() {
 ViewGroup parent = (ViewGroup) getParent();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
 TransitionManager.beginDelayedTransition(parent); parent.removeView(v, p);
 }
  13. onSavedInstance() - In activity public ArrayList<Pair<Class, Object>> history = new

    ArrayList<>(); @Override
 public void onSaveInstanceState(Bundle savedInstanceState) {
 // Save the user's current game state
 savedInstanceState.putSerializable("history", history);
 
 // Always call the superclass so it can save the view hierarchy state
 super.onSaveInstanceState(savedInstanceState);
 }
 

  14. onSavedInstance() - when onCreate() if (savedInstanceState != null) {
 history

    = (…..)savedInstanceState.getSerializable(“history”);
 ArrayList<Pair<Class, Object>> local = new ArrayList<>();
 local.addAll(history);
 
 for (int i = 0; i < local.size(); i++) {
 Pair<Class, Object> node = local.get(i);
 if (node.first == InfoView.class) {
 InfoView.AddMe(this,node.second,true);
 }
 }
 local.clear();
 }
 }
  15. onSavedInstance() — View.addMe public static MyView AddMe(Activity host, Object data

    ,boolean fromHis){ saveState(data) //…… } private void saveState(Object data) {
 MainActivity host =(MainActivity)getContext();
 host.history.add(new Pair(InfoView.class, data));
 }