1. 程式人生 > >Android之AAC架構嘗試

Android之AAC架構嘗試

一、AAC架構的前世今生

    1、關於AAC需先了解一下Android Jetpack,Jetpack 是 Android 軟體元件的集合,使您可以更輕鬆地開發出色的 Android 應用。這些元件可幫助您遵循最佳做法、讓您擺脫編寫樣板程式碼的工作並簡化複雜任務,以便您可以專注於您關心的程式碼。Jetpack 包含與平臺 API 解除捆綁的 androidx.* 軟體包庫。這意味著,它提供向後相容性並且比 Android 平臺更頻繁地更新,從而確保您始終可以獲取最新且最好的 Jetpack 元件版本。

     2、Android Jetpack的優勢

  (1)元件是為協同工作而構建的,不過也可以單獨採用,同時利用 Kotlin 語言功能幫助您提高工作效率;

  (2)Android Jetpack 可管理繁瑣的 Activity(如後臺任務、導航和生命週期管理),以便您可以專注於具體業務;

    (3)Android Jetpack 元件圍繞現代化設計實踐構建而成,具有向後相容性,可以減少崩潰和記憶體洩漏。

     3、Android Architecture Components(簡稱AAC),它是一套新的MVVM架構元件,使App的架構更加健壯,是Android Jetpack的架構元件具有可幫助管理介面元件生命週期、處理資料永續性等的類,以宣告方式將可觀察資料繫結到介面元素。

 相關的API類:

二、程式碼實戰

1、定義model類(省略get 、set方法)

public class NewsDataVo {
    private String id;
    private String newsTitle;
    private String newsContent;
    private String newsUrl;
    private int readNum;
}

2、定義ViewModel

public class NewsViewModel extends AndroidViewModel {

    private MutableLiveData<NewsDataVo> mData;

    private LiveData<NewsDataVo> switchDataMap;

    LiveData<NewsDataVo> getSwitchDataMap() {
        return switchDataMap;
    }

    public NewsViewModel(@NonNull Application application) {
        super(application);
        mData = new MutableLiveData<>();
        switchDataMap = Transformations.switchMap(mData, new Function<NewsDataVo, LiveData<NewsDataVo>>() {
            @Override
            public LiveData<NewsDataVo> apply(NewsDataVo input) {
                MutableLiveData<NewsDataVo> temp = new MutableLiveData<>();
                temp.setValue(input);
                return temp;
            }
        });

    }


    /**
     * 模擬獲取網路資料
     */
    void httpGetData() {
        int len = 10;
        for (int i = 0; i < len; i++) {
            NewsDataVo dataVo = new NewsDataVo();
            dataVo.setId("1223" + i);
            dataVo.setNewsTitle("Android AccArchitecture框架簡介" + i);
            dataVo.setNewsContent("Android Architecture Components,簡稱 AAC,一個處理UI的生命週期與資料的持久化的架構" + i);
            dataVo.setReadNum(i);
            mData.setValue(dataVo);
        }
    }
}

3、定義LifecycleObserver管理View(Activity、Fragment)的生命週期

public class AccLifecycleObserver implements LifecycleObserver {
    private Context context;
    private String tag;

    AccLifecycleObserver(Context context) {
        this.context = context;
        tag = context.getClass().getSimpleName();
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onCreate() {
        Log.i(tag, "onCreate-----" + context.getClass());
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onStart() {
        Log.i(tag, "onStart-----" + context.getClass());
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume() {
        Log.i(tag, "onResume-----" + context.getClass());
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void onPause() {
        Log.i(tag, "onPause-----" + context.getClass());
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onStop() {
        Log.i(tag, "onStop-----" + context.getClass());
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        Log.i(tag, "onDestroy-----" + context.getClass());
    }
}

4、View層互動

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private MainActivity mActivity;
    private NewsViewModel newsViewModel;
    private DataAdapter dataAdapter;
    private List<NewsDataVo> mData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        addObserver();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.do_btn_tv:
                newsViewModel.httpGetData();
                break;
            default:
                break;
        }
    }

    public void initView() {
        mActivity = this;
        mData = new ArrayList<>();
        dataAdapter = new DataAdapter(mData);
        findViewById(R.id.do_btn_tv).setOnClickListener(this);
        RecyclerView recyclerView = findViewById(R.id.data_list_rv);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
        recyclerView.setAdapter(dataAdapter);
    }

    private void addObserver() {
        AccLifecycleObserver observer = new AccLifecycleObserver(mActivity);
        getLifecycle().addObserver(observer);
        ViewModelProvider.AndroidViewModelFactory instance = ViewModelProvider.AndroidViewModelFactory.getInstance(AccApp.sInstance);
        newsViewModel = instance.create(NewsViewModel.class);
        newsViewModel.getSwitchDataMap().observe(mActivity, new Observer<NewsDataVo>() {
            @Override
            public void onChanged(@Nullable NewsDataVo dataVo) {
                assert dataVo != null;
                mData.add(dataVo);
                dataAdapter.notifyDataSetChanged();
            }
        });
    }


    class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewData> {

        private List<NewsDataVo> mData;

        DataAdapter(List<NewsDataVo> mData) {
            this.mData = mData;
        }

        @NonNull
        @Override
        public ViewData onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
            return new ViewData(LayoutInflater.from(mActivity).inflate(R.layout.news_item, viewGroup, false));
        }

        @Override
        public void onBindViewHolder(@NonNull ViewData viewData, int i) {
            NewsDataVo newsDataVo = mData.get(i);
            viewData.numTv.setText(newsDataVo.getReadNum() + "人閱讀");
            viewData.titleTv.setText(newsDataVo.getNewsTitle());
            viewData.contentTv.setText(newsDataVo.getNewsContent());
        }

        @Override
        public int getItemCount() {
            return mData.size();
        }

        class ViewData extends RecyclerView.ViewHolder {
            private ImageView imageView;
            private TextView titleTv;
            private TextView contentTv;
            private TextView numTv;

            public ViewData(@NonNull View itemView) {
                super(itemView);
                imageView = itemView.findViewById(R.id.image_iv);
                titleTv = itemView.findViewById(R.id.title_tv);
                contentTv = itemView.findViewById(R.id.content_tv);
                numTv = itemView.findViewById(R.id.read_num_tv);
            }
        }
    }

 佈局xml檔案

<?xml version="1.0" encoding="utf-8"?>
<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="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/do_btn_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginStart="20dp"
        android:text="渲染資料"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
    <android.support.v7.widget.RecyclerView
        android:id="@+id/data_list_rv"
        android:layout_marginTop="5dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/do_btn_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>




<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/image_iv"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:scaleType="centerCrop"
        android:src="@drawable/timg"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.constraint.Barrier
        android:id="@+id/bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="right"
        app:constraint_referenced_ids="image_iv"
        app:layout_constraintStart_toEndOf="@id/image_iv" />


    <TextView
        android:id="@+id/read_num_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:gravity="right"
        android:text="閱讀人數5人"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/bar"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/title_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="標題"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/bar"
        app:layout_constraintTop_toBottomOf="@+id/read_num_tv" />


    <TextView
        android:id="@+id/content_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="內容"
        android:paddingStart="10dp"
        android:paddingEnd="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/bar"
        app:layout_constraintTop_toBottomOf="@+id/title_tv" />

</android.support.constraint.ConstraintLayout>