zoukankan      html  css  js  c++  java
  • Android Activity数据间传递媒介Intent和任务与后退栈(进阶之路)

    一、简介

     1. 通过进阶之路,学习对多个Activity的操作,最终了解以下知识点:

    • 不通过向导,创建新的Activity及配套布局。
    • 从一个Activity启动另外一个Activity。即,请求操作系统创建一个新的Activity实例,并调用它的onCreate(Bundle)成员方法。
    • 在父Activity(启动方)与子Acitity(被启动方)间进行数据传递。

     2. 了解Activity的任务与后退栈

    二、创建Activity子类与新布局

    • 创建新布局

      选择New-->Layout source file选项,再填相应的配置。

    • 创建Activity子类

      选择New-->Java Class选项,新建一个继承于android.app.Activity的子类。在新的Activity子类中,覆盖方法onCreate(),即可。

    • 为新建的Activity在ActivityManager中进行注册。

      在AndroidManifest.xml文件中,添加新建的Activity,进入注册。

    <activity android:name=".MainActivity">
        <intent-filter>
            <!-- 设置当前Activity为应用的第一个Activity -->
            <action android:name="android.intent.action.MAIN"/>
            <!-- 此应用程序是否显示在系统的程序列表中(此配置仅需在第一个Activity中配置) -->
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

     

    三、启动Activity

      一个Activity启动另一个Activity,最简单的方法就是使用以下Activity方法:

    1 public void startActivity(Intent intent)
    2 {
    3 
    4 }

      从形式上,startActivity(...)方法是Activity类的成员方法,实际上并非是这样。Activity调用startActivity(...)方法,是通过startActivity(...)方法向OS发送消息。准确来说,是通过startActivity(...)在向OS的ActivityManager类发送消息,由ActivityManager类收到消息后,创建Activity实例,并且调用onCreate(Bundel)方法。如下图所示:

                     (此图来自于android书籍权威指南)

    四、Activity间传递数据

      Activity间传递数据是通过Intent实现的,是基于Intent的通信。Intent对象是component与OS进行通信的一个媒介,即通信数据载体。还有一些其它的component,比如:service、broadcast receiver以及content provider。Intent又分为显示Intent与隐式Intent,详细查看Intent详解篇。(http://www.cnblogs.com/naray/p/5300592.html

      1. 使用Intent作为媒介传递数据:

    1 // 创建intent媒介,第一个参数为当前activity实例,第二个参数为将要创建的activity类信息
    2 Intent i = new Intent(getActivity(), CrimeActivity.class);
    3 // 附加extra信息
    4 i.putExtra(CrimeFragment.sExtra_Crime_ID, c.getmId());
    5 // 通过os,activityManager启动activity
    6 startActivity(i);

      2.在新创建的activity中获取附加extra信息,即Intent实例对象,有两个方式获取,即简单直接方式和复杂灵活方式:

    • 简单直接方式,使用getActivity()方法,获取托管的Activity对象,从而获取Intent对象:
      1 // 附加extra信息,在创建activity对象时初始化,通过getIntent()方法获取Intent对象
      2 UUID crimeId = (UUID)getActivity().getIntent().getSerializableExtra(sExtra_Crime_ID);
      3 // 单例数据对象中,获取指定数据
      4 mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);

      PS:此种方式简单直接,但缺点是使用fragment不再是可复用的,因它需要某个具体的Activity托管者。

    • 复杂灵活方式,使用fragment argument传递数据,每个fragment实例都可以有一个Bundle对象。该Bundle包含有键-值对(key-value),可以像附加extra到Activity的Intent中,一样使用Bundle对象。

      (1). 附加extra信息argument给Fragment,要创建Fragment argument,首先需创建Bundle对象,然后,使用Bundle限定类型的“put”方法(类似于Intent的方法),将argument添加到Bundle对象中。如下所示:

    1 // 创建Bundle对象
    2 Bundle args = New Bundle();
    3 // 附加extra数据,以键-值对形式
    4 // put一个boolean类型值
    5 args.putSerializable(EXTRA_MY_OBJECT, myObject);
    6 // put一个int类型值
    7 args.putInt(EXTRA_MY_INT, myInt);
    8 // put一个字符串类型值
    9 args.putCharSequence(EXTRA_MY_STRING, myString);

      (2). 获取Fragment的argument,只需要通过Fragment类的getArgument()方法,即可:

    1 UUID crimeId = (UUID)getArguments().getSerializable(sExtra_Crime_ID);

    Demo:

    获取Intent对象数据,赋给Fragment对象的argument:(CrimePagerActivity.java,使用ViewPager视图显示详情界面)

     1 public class CrimePagerActivity extends SingleFragmentActivity
     2 {
     3     private ViewPager mViewPager;
     4     private ArrayList<Crime> mCrimes;
     5 
     6     public CrimePagerActivity()
     7     {
     8     }
     9 
    10     @Override
    11     public Fragment createFragment()
    12     {
    13         return null;
    14     }
    15 
    16     @Override
    17     public void onCreate(Bundle savedInstanceState)
    18     {
    19         super.onCreate(savedInstanceState);
    20 
    21         // 实例化ViewPager
    22         mViewPager = new ViewPager(this);
    23         // 为ViewPager实例配置资源ID
    24         mViewPager.setId(R.id.viewPager);
    25         // 定制预加载相邻页面的数目
    26         mViewPager.setOffscreenPageLimit(3);
    27         // 设置为Activity的容器
    28         setContentView(mViewPager);
    29 
    30         mCrimes = CrimeLab.get(this).getCrimes();
    31 
    32         // fragment manager
    33         FragmentManager fm = getSupportFragmentManager();
    34         mViewPager.setAdapter(new FragmentStatePagerAdapter(fm)
    35         {
    36             // 获取当前视图的Fragment对象
    37             @Override
    38             public Fragment getItem(int position)
    39             {
    40                 Crime crime = mCrimes.get(position);
    41                 return CrimeFragment.newInstance(crime.getmId());
    42             }
    43 
    44             // 获取数据条数,计算显示视图个数
    45             @Override
    46             public int getCount()
    47             {
    48                 return mCrimes.size();
    49             }
    50         });
    51 
    52         // 设置从列表进入详细界面的具体数据
    53         for (int idx = 0; idx < mCrimes.size(); idx++)
    54         {
    55             UUID code = (UUID) getIntent().getSerializableExtra(CrimeFragment.sExtra_Crime_ID);
    56             if (mCrimes.get(idx).getmId().equals(code))
    57             {
    58                 // 设置界面当前显示的View
    59                 mViewPager.setCurrentItem(idx);
    60                 break;
    61             }
    62         }
    63 
    64         mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
    65         {
    66             @Override
    67             public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
    68             {
    69 
    70             }
    71 
    72             @Override
    73             public void onPageSelected(int position)
    74             {
    75                 Crime crime = mCrimes.get(position);
    76                 if (null != crime.getmTitle())
    77                 {
    78                     setTitle(crime.getmTitle());
    79                 }
    80             }
    81 
    82             @Override
    83             public void onPageScrollStateChanged(int state)
    84             {
    85 
    86             }
    87         });
    88     }
    89 
    90 }

    获取Fragment的argument:(CrimeFragment.java)

      1 public class CrimeFragment extends Fragment
      2 {
      3     private Crime mCrime;
      4     private EditText mEditText;
      5     private Button mDateBtn;
      6     private CheckBox mSolvedCheckBox;
      7     private static final String TAG = "CrimeFragment";
      8     // extra key
      9     public static final String sExtra_Crime_ID = "crimeId";
     10     private static final String sCrime_date = "date";
     11     private static final int REQUEST_DATE = 0x002;
     12 
     13     public static CrimeFragment newInstance(UUID crimeId)
     14     {
     15         Bundle args = new Bundle();
     16         args.putSerializable(sExtra_Crime_ID, crimeId);
     17         CrimeFragment fragment = new CrimeFragment();
     18         fragment.setArguments(args);
     19         return fragment;
     20     }
     21 
     22     @Override
     23     public void onCreate(Bundle savedInstanceState)
     24     {
     25         super.onCreate(savedInstanceState);
     26         // 附加extra信息,在创建activity对象时初始化,通过getIntent()方法获取Intent对象
     27 //        UUID crimeId = (UUID)getActivity().getIntent().getSerializableExtra(sExtra_Crime_ID);
     28         // 单例数据对象中,获取指定数据
     29         UUID crimeId = (UUID) getArguments().getSerializable(sExtra_Crime_ID);
     30         mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
     31     }
     32 
     33     @Override
     34     public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
     35     {
     36         View v = inflater.inflate(R.layout.fragment_crime, parent, false);
     37 
     38         mEditText = (EditText) v.findViewById(R.id.crime_title);
     39         mEditText.setText(mCrime.getmTitle());
     40         mEditText.addTextChangedListener(new TextWatcher()
     41         {
     42             @Override
     43             public void beforeTextChanged(CharSequence s, int start, int count, int after)
     44             {
     45                 mCrime.setmTitle(s.toString());
     46             }
     47 
     48             @Override
     49             public void onTextChanged(CharSequence s, int start, int before, int count)
     50             {
     51 
     52             }
     53 
     54             @Override
     55             public void afterTextChanged(Editable s)
     56             {
     57 
     58             }
     59         });
     60 
     61         mDateBtn = (Button) v.findViewById(R.id.crime_date);
     62         mDateBtn.setText(mCrime.getmDate().toString());
     63 //        mDateBtn.setEnabled(false);
     64         mDateBtn.setOnClickListener(new View.OnClickListener()
     65         {
     66             @Override
     67             public void onClick(View v)
     68             {
     69                 FragmentManager fm = getActivity().getSupportFragmentManager();
     70 //                DatePickerFragment dialog = new DatePickerFragment();
     71                 DatePickerFragment dialog = DatePickerFragment.newInstanceState(mCrime.getmDate());
     72                 dialog.setTargetFragment(CrimeFragment.this, REQUEST_DATE);
     73                 dialog.show(fm, sCrime_date);
     74             }
     75         });
     76 
     77         mSolvedCheckBox = (CheckBox) v.findViewById(R.id.crime_solved);
     78         mSolvedCheckBox.setChecked(mCrime.getmSolved());
     79         mSolvedCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
     80         {
     81             @Override
     82             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
     83             {
     84                 mCrime.setmSolved(isChecked);
     85             }
     86         });
     87 
     88         Button choose = (Button) v.findViewById(R.id.choose_btn);
     89         choose.setOnClickListener(new Button.OnClickListener()
     90         {
     91             @Override
     92             public void onClick(View v)
     93             {
     94                 Intent i = new Intent(Intent.ACTION_SEND);
     95                 i.setType("text/plain");
     96                 i.putExtra(Intent.EXTRA_TEXT, "Choose");
     97                 i.putExtra(Intent.EXTRA_SUBJECT, "Choose Suspect");
     98                 i = Intent.createChooser(i, "Chooser");
     99                 startActivity(i);
    100             }
    101         });
    102 
    103         Button contacter = (Button) v.findViewById(R.id.contact_btn);
    104         contacter.setOnClickListener(new View.OnClickListener()
    105         {
    106             @Override
    107             public void onClick(View v)
    108             {
    109                 Intent i = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
    110                 i.setType("text/plain");
    111                 startActivityForResult(i, 2);
    112             }
    113         });
    114 
    115         return v;
    116     }
    117 
    118     @Override
    119     public void onActivityResult(int requestCode, int resultCode, Intent data)
    120     {
    121         if (resultCode != Activity.RESULT_OK)
    122         {
    123             return;
    124         }
    125 
    126         switch (requestCode)
    127         {
    128             case REQUEST_DATE:
    129             {
    130                 Log.d(TAG, "result data: " + data);
    131                 mDateBtn.setText(data.toString());
    132                 break;
    133             }
    134             default:
    135                 break;
    136         }
    137     }
    138 }

       显示日历picker,创建DatePickerFragment.java:

     1 public class DatePickerFragment extends DialogFragment
     2 {
     3     private static final String EXTRA_DATA = "date";
     4     private Date mDate;
     5 
     6     public DatePickerFragment()
     7     {
     8     }
     9 
    10     public static DatePickerFragment newInstanceState(Date date)
    11     {
    12         Bundle args = new Bundle();
    13         args.putSerializable(EXTRA_DATA, date);
    14 
    15         DatePickerFragment datePickerFragment = new DatePickerFragment();
    16         datePickerFragment.setArguments(args);
    17         return datePickerFragment;
    18     }
    19 
    20     @Override
    21     public Dialog onCreateDialog(Bundle savedInstanceState)
    22     {
    23         // 获取日期数据
    24         mDate = (Date) getArguments().getSerializable(EXTRA_DATA);
    25         int year = 0, month = 0, day = 0;
    26 
    27         if (null != mDate)
    28         {
    29             // calender
    30             Calendar calendar = Calendar.getInstance();
    31             calendar.setTime(mDate);
    32             year = calendar.get(Calendar.YEAR);
    33             month = calendar.get(Calendar.MONTH);
    34             day = calendar.get(Calendar.DAY_OF_MONTH);
    35         }
    36 
    37         View v = getActivity().getLayoutInflater().inflate(R.layout.dialog_date, null);
    38 
    39         DatePicker datePicker = (DatePicker) v.findViewById(R.id.dialog_date_datepicker);
    40         datePicker.init(year, month, day, new DatePicker.OnDateChangedListener()
    41         {
    42             @Override
    43             public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth)
    44             {
    45                 mDate = new GregorianCalendar(year, monthOfYear, dayOfMonth).getTime();
    46                 getArguments().putSerializable(EXTRA_DATA, mDate);
    47             }
    48         });
    49 
    50         return new AlertDialog.Builder(getActivity())
    51                 .setView(v)
    52                 .setTitle(R.string.date_picker_dialog)
    53                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
    54                 {
    55                     @Override
    56                     public void onClick(DialogInterface dialogInterface, int which)
    57                     {
    58                         sendResult(Activity.RESULT_OK);
    59                     }
    60                 }).create();
    61     }
    62 
    63     private void sendResult(int resultCode)
    64     {
    65         if (null == getTargetFragment())
    66         {
    67             return;
    68         }
    69 
    70         // 创建Intent对象
    71         Intent i = new Intent();
    72         // 设置传递的数据
    73         i.putExtra(EXTRA_DATA, mDate);
    74         // 同一Activity间传递数据,可以通过getTargetFragment()方法,获取另一个fragment实例,
    75         // 手动调用onActivityResult(...)方法,传递数据
    76         getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, i);
    77     }
    78 }

      1. Activity.onActivityResult(...)方法是ActivityManager在子activity销毁后调用的父activity方法。处理activity间的数据返回时,无需亲自动手,ActivityManager会自动调用Activity.onActivityResult(...)方法。父Activity接收到Activity.onActivityResult(...)方法的调用后,其FragmentManager会调用对应fragment的Fragment.onActivityResult(...)方法。

      说白了就是Activity托管各自的fragment,在子Activity销毁后,ActivityManager会自己调用父类的Activity方法。在处理Activity间的数据返回时,无需亲自动手,ActivityManager会自动调用Activity.onActivityResult(...)方法。

      2. 在同一Activity托管两个Fragment间的数据返回时,借用Fragment.onActivityResult(...)方法。因此,直接调用目标fragment的Fragment.onActivityResult(...)方法。即可实现数据的回传,该方法有我们需要的信息:

    • 一个与传入setTargetFragment(...)方法相匹配的请求代码,用以告知目标fragment返回结果来自于哪里。
    • 一个决定下一步该采取什么行动的结果代码。
    • 一个含有extra数据信息的Intent。

    五、任务与后退栈

      在每一个应用中,Android OS都使用任务来跟踪用户的状态,任务就是Activity栈。栈底Activity称为基Activity,栈顶Activity是正在显示的Activity,当用户点击回退键时,栈顶Activity会被从栈中弹出(销毁)。如果,后退的Activity是基Activity,那么就会回到OS主屏幕。

      

                         (此图来自于Android书籍权威指南)

      1. 通过在显示Intent设置Activity_flag,来管理任务,即Activity栈中的Activity。

      2. 对显示Intent设置Activity_flag_new_task,新启动的Activity在新的任务栈中。

      3. 在Intent中可以设置多个flag。

    (未完待续...)

  • 相关阅读:
    Opennebula4.2管理端和节点SSH模式的安装配置
    shell操作mysql之增删改查
    Linux常用服务部署与优化之NFS篇
    Linux常用服务部署与优化之Samba篇
    sql编程小结
    mysql5.7.11编译安装以及修改root密码小结
    基于centOS6.7搭建LAMP(httpd-2.4.18+mysql-5.5.47+php-5.6.16)环境
    php实现文件上传下载功能小结
    zabbix搭建
    mysql主从复制
  • 原文地址:https://www.cnblogs.com/naray/p/5281783.html
Copyright © 2011-2022 走看看