频道栏目
首页 > 资讯 > Android > 正文

Android学习笔记四之Activity

16-06-15        来源:[db:作者]  
收藏   我要投稿

1、什么是Activity

Activity是Android四大组件之一,用于显示View。Activity是一个应用程序组件,提供一个用户交互的接口,其本身是没有界面的,Activity类创建一个窗口,在上面可以绘制用户接口。窗口通常充满屏幕,也可以小于屏幕而悬浮于其他窗口之上。

开发者可以通过Activity类提供的setContentView(View)接口将View放到Activity创建的窗口上。一个程序一般由多个Activity组成,他们通常是松耦合关系。一个Activity可以启动另外一个Activity。每次一个Activity启动,前一个Activity就停止,但是Android系统会保留Activity在一个栈上,当用户完成当前Activity然后点击back按钮时,它就会被弹出栈并被销毁。所有的Activity类必须在AndroidManifest.xml文件中注册,不注册会报错。例如:

<activity android:name=".BaseActivity" />
<activity android:name=".activity.AboutCSDNActivity" />
<activity android:name=".activity.BlogOsphereActivity" />
<activity android:name=".activity.FeedBackActivity" />
<activity android:name=".activity.WebActivity" />
<activity android:name=".activity.AllBloggerActivity" />
<activity android:name=".activity.BlogDetailActivity" />

2、activity的生命周期方法

下图是Android api中所提供的Activity生命周期图

由图可以看出,Activity有如下生命周期方法,分别是:

public class Activity extends ApplicationContext {

protected void onCreate(Bundle savedInstanceState);

protected void onStart();

protected void onResume();

protected void onPause();

protected void onStop();

protected void onDestroy();

 }

一个Activity启动,执行生命周期方法顺序是:onCreate -> onStart -> onResume;当一个Activity被Kill掉时候,执行生命周期方法顺序是:onPause -> onStop -> onDestroy。这是一个完整的生命周期循环。当一个应用正在运行,由于其它应用中断,比如电话来了等,执行的生命周期方法是onPause -> onStop,挂断电话恢复到当前应用,执行的生命周期方法是onStart -> onResume;如果当前应用的Activity是Theme为Translucent(半透明)或者Dialog时,那么中断就是onPause ,恢复的时候onResume。

2.1、各种生命周期方法在系统中的作用

onCreate方法:在这里创建界面,可以实现一些界面的初始化工作 onStart方法:在onCreate方法之后被调用,或者Activity从stop状态转换为Active状态被调用,可以实现数据的请求 onResume方法:在 Activity 从 Pause 状态转换到 Active 状态时被调用。 onPause方法:在 Activity 从 Active 状态转换到 Pause 状态时被调用。在这里可以保存一些数据,在onResume方法中可以读取这里保存的数据。 onStop方法:在 Activity 从 Active 状态转换到 Stop 状态时被调用。一般我们在这里保存 Activity 的状态信息。 onDestroy方法:在 Activity 被结束时调用,它是被结束时调用的最后一个方法,在这里一般做些释放资源,清理内存等工作。

onPause,onstop, onDestroy,三种状态下 activity都有可能被系统kill掉

2.2、Activity的四种状态

Activity有四种状态分别是:

Running状态 Stopped状态 Paused状态 Destroyed状态

生命周期方法在各个状态被调用时机如下图:

由上图可以看出:

当Running状态的时候,调用onPause方法可以切换到Pauseed状态。 当在Paused状态的时候,调用onResume方法可以切换到Running状态,调用onStop方法可以切换到Stopped状态,如果应用被退出就切换到Destroyed状态。 当处在Stopped状态时候,调用onRestart方法、onStart方法、onResume方法会切换到Running状态,调用onDestroy方法或者应用被退出就会切换到Destroyed状态。

3、Activity之间的通信

在 Android 中,不同的 Activity 实例可能运行在一个进程中,也可能运行在不同的进程中。因此我们需要一种特别的机制帮助我们在 Activity 之间传递消息。Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。

Intent负责对操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。

在应用中,我们可以通过两种形式来使用Intent:

直接Intent:指定了component属性的Intent(setClass(Context, Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。

间接Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。
对于直接Intent,Android不需要去做解析,因为目标组件已经很明确。

Android需要解析的是那些间接Intent,通过解析,将 Intent映射给可以处理此Intent的Activity、IntentReceiver或Service。Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的Intent,最终找到匹配的Intent。

通过setClass传递消息:

 Intent intent =new Intent(CurrentActivity.this,OtherActivity.class);
 Bundle bundle =new Bundle();
 bundle.putBoolean("boolean_key", true);
 bundle.putString("string_key", "string_value"); 
 intent.putExtra("key", bundle);
 startActivity(intent);

另一个Activity解析消息:

Intent intent =getIntent(); 
 Bundle bundle =intent.getBundleExtra("key"); 
 bundle.getBoolean("boolean_key");
 bundle.getString("string_key");

除了使用intent之外还可以使用sharedpreference传递消息:

 // 写入 SharedPreferences 
 SharedPreferences preferences = getSharedPreferences("name", MODE_PRIVATE); 
 Editor editor = preferences.edit(); 
 editor.putBoolean("boolean_key", true); 
 editor.putString("string_key", "string_value"); 
 editor.commit(); 

 // 读取 SharedPreferences 
 SharedPreferences preferences = getSharedPreferences("name", MODE_PRIVATE); 
 preferences.getBoolean("boolean_key", false); 
 preferences.getString("string_key", "default_value");

一个Activity向另外一个Activity传递消息,后一个Activity传回给前一个

例如:A.Activity向B.Activity传递一些消息,当B.Activity关闭的时候回传一些消息给A.Activity

//在A.Activity中加入:

button.setOnClickListener(new OnClickListener(){
   @Override
   public void onClick(View arg0) {
  Intent intent = new Intent();
  intent.setClass(a.this, b.class);
  Bundle bundle = new Bundle();
  bundle.putString("v_id",i_id);
  intent.putExtras(bundle);
  startActivityForResult(intent,0);
  overridePendingTransition(R.anim.zoomin, R.anim.zoomout);
   }

 });

//在B.Activity中加入:
String v_id = this.getIntent().getExtras().getString("v_id");



//在B.Activity 中加入。当关闭b时,传递数据name给a:

   b_close.setOnClickListener(new OnClickListener(){
   @Override
   public void onClick(View arg0) {
   Intent intent = getIntent();
   Bundle bundle = new Bundle();
   bundle.putString("name",name);
   intent.putExtras(bundle);
   setResult(RESULT_OK,intent);
   finish();
   }
});



//在A.Activity中加入,接受回调信息name
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data_intent){
super.onActivityResult(requestCode, resultCode, data_intent);
 if(resultCode == RESULT_CANCELED)
setTitle("cancel");
 else if (resultCode == RESULT_OK){
Bundle bundle = data_intent.getExtras();
if(bundle != null){
//获取b传送的数据
  String name = bundle.getString("name");  
}
   }
}

Android 提供了包括 SharedPreferences 在内的很多种数据存贮方式,比如 SQLite,文件等,程序员可以通过这些 API 实现 Activity 之间的数据交换。如果必要,我们还可以使用 IPC 方式。

4、Activity的四种加载模式

Activity有四种加载模式,分别是:standard模式、singleTop模式、singleTask模式、singleInstance模式(其中standard模式和singleTop模式是一组、singleTask模式和singleInstance模式是一组),默认加载模式是standard模式。

四种加载模式的区别:

1、standard:标准模式(默认模式),一旦调用startActivity()方法就会产生一个新的Activity实例。 不需要在launchMode属性配置

/**
 * 默认(standard)加载模式
 * 
 */
public class ActivityOne extends Activity implements OnClickListener
{
private TextView textView;// 显示文本
private Button button;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    textView = (TextView) findViewById(R.id.textView);
    button = (Button) findViewById(R.id.button);
    button.setText("go to ActivityOne");
    button.setOnClickListener(this);
    textView.setText(this + "");
}

@Override
public void onClick(View v)
{
    Intent intent = new Intent();
    intent.setClass(ActivityOne.this, ActivityOne.class);// 跳转
    startActivity(intent);
}
}

AndroidManifset.xml文件配置:


    
   
   
   

2、singleTop:如果Activity实例位于栈顶,就不产生新的实例,直接使用栈顶的实例,否则,就会产生一个新的实例。
例如:现在Task栈元素为A-B-C-D(D在栈顶),这时候给D发一个启动Intent,如果D是 “standard”模式的,则生成D的一个新实例,栈状态为A-B-C-D-D。如果D是singleTop模式的话,则不会生成D的新实例,栈状态仍为A-B-C-D。如果这时候给B发Intent的话,不管B的launchMode是“standard”还是“singleTop”,都会生成B的新实例,栈状态变为A-B-C-D-B。

/**
 * singleTop模式
 */
public class ActivityOne extends Activity implements OnClickListener
{
private TextView textView;// 显示文本
private Button button;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    textView = (TextView) findViewById(R.id.textView);
    button = (Button) findViewById(R.id.button);
    button.setText("go to ActivityOne");
    button.setOnClickListener(this);
    textView.setText(this + "");
}

@Override
public void onClick(View v)
{
    Intent intent = new Intent();
    intent.setClass(ActivityOne.this, ActivityOne.class);// 跳转
    startActivity(intent);
}
}

AndroidManifset.xml文件配置:







3、singleTask:每次调用都会使用这个实例,不会去产生新的实例了。

AndroidManifset.xml文件配置:









4、singleInstance:跟singleTask模式基本上是一样,只有一个区别:在这个模式下的Activity实例与其他Activity处在不同的Task中,此实例所处的Task中只能有这个Activity实例,不能有其他的实例。

AndroidManifaset.xml文件配置:









5、Activity的创建和启动

5.1、Activity的创建流程

Activity创建需要经历如下的步骤:

(1) 自定义Activity类名,继承Activity类或者其子类,使用AS开发,一般继承AppCompatActivity类

public class BaseActivity extends AppCompatActivity {}

(2) 重写onCreate方法,并在该方法中调用setContentView方法

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(View);
}

(3) 在AndroidManiFest.xml文件中注册Activity,必须要注册,不注册会报错

  
    
        
            

            
        

    
    
    
    
    
    
    
    
    

(4) 启动Activity,通过调用startActivity(Intent)启动。

Intent intent = new Intent(getApplicationContext(), BlogDetailActivity.class);
   intent.putExtra("username", blogOspheres.get(position).getUserName());
   intent.putExtra("name", blogOspheres.get(position).getName());
   startActivity(intent);

(5) 销毁Activity,通过调用Finish()方法

        @Override
        public void onClick(View v) {
            finish();
        }

5.2、Activity启动的几种方式

第一种:显示启动

startActivity(new Intent(当前Activity,要启动的Activity.class));

//通过intent的ComponentName启动
ComponentName componentName = new ComponentName("当前Activity的全限定类名","启动Activity的全限定类名") ;
Intent intent = new Intent() ;
intent.setComponent(componentName) ;
startActivity(intent) ;

Intent intent = new Intent("android.intent.action.MAIN");
intent.setClassName("当前Activity的全限定类名","启动Activity的全限定类名");
startActivity(intent);

第二种:隐式启动

 
 
 
 
 

Intent intent=new Intent("com.example.android.tst.SecondActivity"); 
startActivity(intent);

第三种:启动APK

Intent intent = getPackageManager().getLaunchIntentForPackage
("apk第一个启动的Activity的全限定类名") ;
if(intent != null) startActivity(intent) ;

6、系统给我们提供的Activity

以下是Android系统给我们提供的常用的Activity

拨打电话

Uri uri = Uri.parse("tel:10010");
Intent intent = new Intent(Intent.ACTION_DIAL, uri);
startActivity(intent);

发送短信

Uri uri = Uri.parse("smsto:10010");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
intent.putExtra("sms_content", "Hello");
startActivity(intent);

发送彩信

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra("sms_body", "Hello");
Uri uri = Uri.parse("content://media/external/images/media/23");
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType("image/png");
startActivity(intent);

打开浏览器:

Uri uri = Uri.parse("http://www.baidu.com");
Intent intent  = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

发送电子邮件

Uri uri = Uri.parse("mailto:zhangsan@163.com");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(intent);

// 给zhangsan@163.com发邮件发送内容为“Hello”的邮件
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, "zhangsan@163.com");
intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
intent.putExtra(Intent.EXTRA_TEXT, "Hello");
intent.setType("text/plain");
startActivity(intent);
// 给多人发邮件
Intent intent=new Intent(Intent.ACTION_SEND);
String[] mailTos = {"zhangsan@163.com", "lisi@163.com"}; // 收件人
String[] copyTos = {"wangwu@sina.com", "zhaoliu@sina.com"}; // 抄送
String[] secretTos = {"liuba@126.com", "sunjiu@126.com"}; // 密送
intent.putExtra(Intent.EXTRA_EMAIL, mailTos);
intent.putExtra(Intent.EXTRA_CC, copyTos);
intent.putExtra(Intent.EXTRA_BCC, secretTos);
intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
intent.putExtra(Intent.EXTRA_TEXT, "Hello");
intent.setType("message/rfc822");
startActivity(intent);

显示地图:

Uri uri = Uri.parse("geo:23.20,113.30");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

多媒体播放:

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/music.mp3");
intent.setDataAndType(uri, "audio/mp3");
startActivity(intent);

获取SD卡下所有音频文件,然后播放第一首

Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

打开摄像头拍照:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
startActivityForResult(intent, 0);

// 取出照片数据
Bundle extras = intent.getExtras(); 
Bitmap bitmap = (Bitmap) extras.get("data");

另一种:
调用系统相机应用程序,并存储拍下来的照片
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
time = Calendar.getInstance().getTimeInMillis();
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment
.getExternalStorageDirectory().getAbsolutePath()+"/tucue", time + ".jpg")));
startActivityForResult(intent, ACTIVITY_GET_CAMERA_IMAGE);

获取并剪切图片

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
intent.putExtra("crop", "true"); // 开启剪切
intent.putExtra("aspectX", 1); // 剪切的宽高比为1:2
intent.putExtra("aspectY", 2);
intent.putExtra("outputX", 20); // 保存图片的宽和高
intent.putExtra("outputY", 40); 
intent.putExtra("output", Uri.fromFile(new File("/mnt/sdcard/temp"))); // 保存路径
intent.putExtra("outputFormat", "JPEG");// 返回格式
startActivityForResult(intent, 0);

剪切特定图片

Intent intent = new Intent("com.android.camera.action.CROP"); 
intent.setClassName("com.android.camera", "com.android.camera.CropImage"); 
intent.setData(Uri.fromFile(new File("/mnt/sdcard/temp"))); 
intent.putExtra("outputX", 1); // 剪切的宽高比为1:2
intent.putExtra("outputY", 2);
intent.putExtra("aspectX", 20); // 保存图片的宽和高
intent.putExtra("aspectY", 40);
intent.putExtra("scale", true);
intent.putExtra("noFaceDetection", true); 
intent.putExtra("output", Uri.parse("file:///mnt/sdcard/temp")); 
startActivityForResult(intent, 0);

进入手机设置界面:

Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);  
startActivityForResult(intent, 0);

安装apk应用:

Uri installUri = Uri.fromParts("package", "xxx", null);   
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);

卸载apk应用:

Uri uri = Uri.fromParts("package", packageName, null);  
Intent it = new Intent(Intent.ACTION_DELETE, uri);  
startActivity(it); 

打开联系人:

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(People.CONTENT_URI);
startActivity(intent);

查看指定联系人:

Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, info.id);//info.id联系人ID
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(personUri);
startActivity(intent);

7、Activity的安全退出

两种方法:

第一种:写一个BaseActivity,项目中所有的Activity都继承于这个BaseActivity,在BaseActivity中记录每一个Activity,退出应用的时候将所有的Activity销毁

 //用一个集合管理所有的activity
public final static LinkedList mBaseActivities = new LinkedList();
public static BaseActivity mBaseActivity;

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    synchronized (mBaseActivities) {
        mBaseActivities.add(this);
    }
}

 @Override
protected void onResume() {
super.onResume();
mBaseActivity = this;
}

@Override
protected void onPause() {
super.onPause();
mBaseActivity = null;
}

@Override
protected void onDestroy() {
    super.onDestroy();
    synchronized (mBaseActivities) {
        mBaseActivities.remove(this);
    }
}

//安全退出程序
public static void exitApp() {
    LinkedList activityCopy;
    //复制一份activity
    synchronized (mBaseActivities) {
        activityCopy = new LinkedList(mBaseActivities);
    }
    for (BaseActivity baseActivity : activityCopy) {
        baseActivity.finish();
    }
    //杀死当前进程
    android.os.Process.killProcess(android.os.Process.myPid());
}

第二种方法:退出的时候发送广播,销毁所有的Activity

8、Activity切换动画设置

在Activity切换的时候设置切换动画有两种方式:

第一种:在Activity跳转的时候设置,即是在startActivity方法之后设置,代码如下:

A.Activity跳转到B.Activity时,在startActivity()方法后面设置

 //第一个参数是activity离开时的动画,第二个参数是activity进入时的动画
 overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out);

B.Activity回转到A.Activity时,在Finish()方法后面设置

finish();
overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out);

优化思路:可以将整个应用里面Activity相同的操作抽取到一个类里面,在BaseActivity中实例化,每一次设置动画或者进行Activity相关操作(比如,Activity跳转、传递参数等),直接调用方法即可,代码如下:

public class Opration {

private Intent mIntent = new Intent();
private Activity mContext = null;
private BaseApplication application = null;

public Opration(Activity mContext) {
    this.mContext = mContext;
    application = (BaseApplication) this.mContext.getApplicationContext();
}

/**
 * 跳转Activity
 *
 * @param activity 需要跳转至的Activity
 */
public void forward(Class activity) {
    mIntent.setClass(mContext, activity);
    mContext.startActivity(mIntent);
    mContext.overridePendingTransition(R.anim.base_slide_right_in, R.anim.base_slide_remain);
}

/**
 * 设置传递参数
 *
 * @param key   参数key
 * @param value 数据传输对象
 */
public void addParameter(String key, Bundle value) {
    mIntent.putExtra(key, value);
}

/**
 * 设置传递参数
 *
 * @param key   参数key
 * @param value 数据传输对象
 */
public void addParameter(String key, String value) {
    mIntent.putExtra(key, value);
}
}

第二种设置切换动画的方法:在样式文件里面设置


修改Theme


最后在AndroidManifest.xml文件中设置:


9、Activity其他设置

9.1、横竖屏切换问题

在Android中,默认状态下APP横竖屏切换的时候会销毁当前的Activity实例,然后重新创建Activity实例,横竖屏切换时Activity的生命周期方法顺序是:onPause-> onStop-> onDestory-> onCreate->onStart->onResume。在一些特殊情况下,我们需要对横竖屏切换进行一些处理,以下是常用的处理:

禁止屏幕横竖屏切换

在AndroidManifest.xml中为Activity添加一个属性:android:screenOrientation, 这个属性有下述可选值:

unspecified:默认值 由系统来判断显示方向.判定的策略是和设备相关的,所以不同的设备会有不同的显示方向。 landscape:横屏显示(宽比高要长) portrait:竖屏显示(高比宽要长) user:用户当前首选的方向 behind:和该Activity下面的那个Activity的方向一致(在Activity堆栈中的) sensor:有物理的感应器来决定。如果用户旋转设备这屏幕会横竖屏切换。 nosensor:忽略物理感应器,这样就不会随着用户旋转设备而更改了(”unspecified”设置除外)。
横竖屏切换的时候加载不同的布局

1)准备两套不同的布局,Android会自己根据横竖屏加载不同布局: 创建两个布局文件夹:layout-land横屏,layout-port竖屏 然后把这两套布局文件放在这两个文件夹里,文件名一样,Android就会自行判断,然后加载相应布局了!

2 )自己在代码中进行判断
我们一般是在onCreate()方法中加载布局文件的,我们可以在这里对横竖屏的状态做下判断,关键代码如下:

if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){  
 setContentView(R.layout.横屏);
}  

else if (this.getResources().getConfiguration().orientation ==Configuration.ORIENTATION_PORTRAIT) {  
setContentView(R.layout.竖屏);
}
状态保存问题

通过一个Bundle savedInstanceState参数即可完成,有三个核心方法:

onCreate(Bundle savedInstanceState);
onSaveInstanceState(Bundle outState);
onRestoreInstanceState(Bundle savedInstanceState);

在onSaveInstanceState(Bundle outState);里面将需要保存的数据放入到Bundle里面,然后在 onCreate(Bundle savedInstanceState);或者onRestoreInstanceState(Bundle savedInstanceState);中将数据取出。

注意:取出数据的时候要进行判空操作。

相关TAG标签
上一篇:AndroidStuio快速发布开源项目到Jcenter/Bintray
下一篇:iOS开发——CocoaPods安装与使用
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站