美文网首页
Android学习总结

Android学习总结

作者: lulu10922 | 来源:发表于2018-08-31 17:33 被阅读0次
    1. activity是Android SDK中Activity的一个实例,负责控制各组件与用户的交互

    2. 布局定义了一系列组件,包括Button、TextView、 RecyclerView。布局和组件之间的关系可用下图表示:


      布局和组件的关系

    常用组件和布局的继承关系如下图:


    常用组件和布局的继承关系
    1. 项目的app/res/values目录下保存了一系列的资源,包括字符串资源,图片资源等,包括布局也是资源的一种。它们都通过资源ID被引用。如果控件也需要被引用,则在xml文件中定义它们时,可以加上android:id属性,为其设置ID。
    2. xml布局是如何转换为视图对象的呢?activity子类被创建后,onCreate(Bundle)方法会被调用,它再调用
    public void setContentView(int layoutRestId)
    

    根据传入的布局资源ID,使用LayoutInflater类实例化该布局中定义的每一个View。activity子类都需要声明在AndroidManifest.xml配置文件中,在该文件中会设置一个launcher activity,app启动时会创建该activity。

    1. MVC设计模式。MVC即模型,视图,控制,activity或者fragment(service还未学习)可以作为控制器,它们将视图即View实例对象显示在屏幕,将模型(实例类)中的数据显示更新在屏幕上。GeoQuiz项目的MVC示意图如下:


      MVC模式示意图
    1. activity的生命周期。
      Activity生命周期

    在activity的各个阶段,Android系统会自动调用相应的方法。重载这些方法,添加log,切换手机横竖屏,可以通过logcat看到activity的生命周期中相应方法的调用。

    1. 保存数据以应对设备旋转。
    protected void onSaveInstanceState(Bundle outstate)
    

    该方法通常在onStop()方法前被调用,除非用户按了后退键。该方法的默认实现把所有activity视图状态保存在Bundle中,Bundle是一种存储键-值对的一种结构。可以通过覆盖onSaveInstanceState()方法,将一些信息保存在Bundle中:

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        Log.i(TAG, "onSaveInstanceState");
        savedInstanceState.putInt(KEY_INDEX, mCurrentIndex);
        savedInstanceState.putBoolean(KEY_IS_CHEATER, mIsCheater);
    }
    

    在onCreate()方法中获取信息:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate(Bundle) called");
        setContentView(R.layout.activity_quiz);
    
        if (savedInstanceState != null) {
            mCurrentIndex = savedInstanceState.getInt(KEY_INDEX);
            mIsCheater = savedInstanceState.getBoolean(KEY_IS_CHEATER);
        }
        ...
    }
    

    还可以存BooleanArray。操作系统会将Bundle对象放入activity记录中,可以理解为暂存。覆盖onSaveInstanceState()保存当前activity的小的或状态的数据;覆盖onStop()方法,保存永久性数据,如用户编辑的文字等。(?如何理解?)

    1. tools命名空间。使用该命名空间,可以覆盖某个组件的任意属性,改属性仅在预览中生效。
    2. 启动activity并互相传递数据。一个activity启动另一个activity最简单的方式是用startActivity方法:
    public void startActivity(Intent intent)
    

    activity调用该方法后,调用请求发给了操作系统的ActivityManager。ActivityManager启动哪个activity呢?答案在传入的参数intent。intent有很多构造方法,其中一种为:

    public Intent(Context packageContext, Class<?> cls)
    

    传入的Class类型参数告诉ActivityManager要启动的activity,Context类型参数告诉ActivityManager在哪里可以找到它(?不是在manifest配置文件中声明了吗?)。可以在startActivity(Intent intent)的intent上附加上extra信息,传递给启动的activity。如同在Bundle中保存信息一样,extra信息也是一种键值对,在子activity中提供一个借口,父activity把信息通过借口传过来即可,无需关心“键”是什么样的:

    //子activity
    public static Intent newIntent(Context packageContext, boolean answerIsTrue) {
         Intent intent = new Intent(packageContext, CheatActivity.class);
         intent.putExtra(EXTRA_ANSWER_IS_TRUE, answerIsTrue);
         return intent;
    }
    //父activity
    mCheatButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //start cheatactivity
            boolean answerIsTrue = mQuestionBank[mCurrentIndex].isAnswerTrue();
            Intent intent = CheatActivity.newIntent(QuizActivity.this, answerIsTrue);
            startActivity(intent);
        }
    });
    

    子activity在onCreate方法中就可以获取该extra信息:

    mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false);
    

    可以用intent传递更多的信息,使用多参数版本的intent构造函数即可(还未实践)。

    以上是父activity传递信息给子activity,要获取子activity的信息,可以修改startActivity方法:

    startActivityForResult(intent, REQUEST_CODE_CHEAT);
    

    子activity可以调用:

    public final void setResult(int resultCode)
    public final void setResult(int resultCode, Intent intent)
    

    如果子activity没有调用setResult,而父activity又是调用startActivityForResult启动子activity的,父activity会收到Activity.RESULT_CANCELLED。在项目实践中,子activity的Button监听回调被调用后,它设置了返回结果:

    private void setAnswerShownResult(boolean isAnswerShown) {
        Intent intent = new Intent();
        intent.putExtra(EXTRA_ANSWER_SHOWN, isAnswerShown);
        setResult(RESULT_OK, intent);
    }
    
    public static boolean wasAnswerShown(Intent result) {
        return result.getBooleanExtra(EXTRA_ANSWER_SHOWN, false);
    }
    

    ActivityManager在子activity被销毁后调用父类的onActivityResult()方法,故父activity要重载该方法:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != Activity.RESULT_OK) {
            return;
        }
    
        if (requestCode == REQUEST_CODE_CHEAT) {
            if (data == null) {
                return;
            }
            mIsCheater = CheatActivity.wasAnswerShown(data);
        }
    }
    

    这里,解析信息放在了子activity定义的一个接口中,因为“键”存在子activity中,最终的还是通过intent来解析到的。

    1. Fragment。fragment与activity很类似,它也是负责创建并管理用户界面,与模型对象进行交互。fragment的生命周期与activity类似,但是fragment的生命周期方法由它的托管activity而不是操作系统调用。fragment并没有像activity一样在onCreate方法中完成布局和组件view的实例化,而是在onCreateView方法中完成的,如下:
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_crime, container, false);
    
        mTitleField = v.findViewById(R.id.crime_title);
        ...
    
        mDateButton = v.findViewById(R.id.crime_date);
        ...
    
        mSolvedCheckBox = v.findViewById(R.id.crime_solved);
        ...
    
        return v;
    }
    

    第二个参数是视图的父视图。以上fragment类中完成了主要的工作,但它的视图显然还无法显示出来,它需要托管给activity。Activity类中添加了FragmentManager类,它负责管理fragment并将它们的视图添加到activity的视图层级结构中。具体做法:

    public class CrimeActivity extends SingleFragmentActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_fragment);
        
            FragmentManager fm = getSupportFragmentManager();
            Fragment fragment = fm.findFragmentById(R.id.fragment_container);
        
            if (fragment == null) {
                fragment = new createFragment();
                fm.beginTransaction()
                        .add(R.id.fragment_container, fragment)
                        .commit();
            }
        }
    }
    

    fragment事务的add接口,第一个参数为容器视图资源ID,第二个参数是要加入的Fragment。二者视图关系可用下图表示,fragment视图要放置在activity的视图层级结构中:


    CrimeActivity托管着CrimeFragment
    1. RecyclerView。RecyclerView是ViewGroup的子类,每一个列表项是作为View子对象来显示的。它们的显示依赖于两个类:ViewHolder和Adapter。在控制器中重载这两个类。实践项目中RecyclerView作为fragment布局的一个组件,在onCreateView方法中要先调用:
    mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    

    接下来,控制器把要显示的模型对象(一般是ArrayList对象?)作为参数构造了一个Adapter,然后调用:

    mCrimeRecyclerView.setAdapter(mAdapter);
    

    接着,Adapter调用getItemCount()方法获取要显示的列表项的个数,根据该个数,循环调用onCreateViewHolder( ViewGroup viewGroup, int i)和onBindViewHolder(CrimeHolder crimeHolder, int i)。ViewHolder的任务是什么呢?它首先会把列表项布局实例化,然后再通过各组件的ID,找到它们的引用。在onBindViewHolder,Adapter会把要显示的模型参数传递给ViewHolder,它通过组件显示在屏幕上。项目实践中相关代码示例:

    private class CrimeHolder extends RecyclerView.ViewHolder
                implements View.OnClickListener {
        ......
        public CrimeHolder(LayoutInflater inflater, ViewGroup parent) {
            super(inflater.inflate(R.layout.list_item_crime, parent, false));
        
            itemView.setOnClickListener(this);
            mTitleTextView = itemView.findViewById(R.id.crime_title);
            mDateTextView = itemView.findViewById(R.id.crime_date);
            mSolvedImageView = itemView.findViewById(R.id.crime_solved);
        }
        public void bind(Crime crime) {
            mCrime = crime;
            mTitleTextView.setText(mCrime.getTitle());
            mDateTextView.setText(mCrime.getDate().toString());
            mSolvedImageView.setVisibility(mCrime.isSolved() ? View.VISIBLE : View.GONE);
        }
        ......
    }
    
    
    @Override
    private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
        ......
        public CrimeHolder onCreateViewHolder( ViewGroup viewGroup, int i) {
            LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
        
            return new CrimeHolder(layoutInflater, viewGroup);
        }
        
        @Override
        public void onBindViewHolder(CrimeHolder crimeHolder, int i) {
            Crime crime = mCrimes.get(i);
            crimeHolder.bind(crime);
        }
        ......
    }
    

    相关文章

      网友评论

          本文标题:Android学习总结

          本文链接:https://www.haomeiwen.com/subject/jklewftx.html