LogCat

Android Studio中已经默认添加了LogCat工具,macOS使用control+6,Win使用Alt+6打开。
Android中的日志工具类是Log(android.util.Log),这个类中提供了如下方法:

Log.v() //这个方法打印最为琐碎的,意义最小的日志信息,对应级别verboseLog.d() //这个方法打印一些调试信息,对应级别debugLog.i() //这个方法打印一些警告,提示程序的潜在风险,对应级别warnLog.e() //这个方法用于打印错误信息,对应级别error

尝试

onCreate()方法中添加一行打印日志的语句。
Log.d(“HelloWorldActivity”, “onCreate execute”);
函数传入两个参数,第一个是tag,一般传入当前的类名,主要用于过滤信息,第二个参数是msg,即想要打印的具体内容。

Activity

创建活动

定义一个Activity类的子类,在子类中重写onCreate()方法。

创建和裁剪布局

res/layout目录中新建一个XML布局文件。
尝试添加一个Button

其中@+id/button_1是在XML语言中定义一个id的语法。
+去掉,@id/button_1就是引用id的语法。
随后,android:layout_width指定元素宽度,match_parent表示和父元素一样。
android:layout_height自然就是高度,wrap_content表示恰好容纳就可以了。
android:text指定元素中显示的文字内容。

应用布局

onCreate()中写入:setContentView(R.layout.first_layout);传入一个布局文件的id

注册

所有的活动需要在AndroidManifest.xml中注册才能生效。

                                                        

可以看到,活动的注册声明要放在标签内,这里是通过标签来对活动进行注册的。
首先我们要使用android:name来制定具体注册哪一个活动,这里的.FirstActivitycom.example.activitytest.FirstActivity的缩写。由于最外层的标签中已经通过package属性指定了用户的包名,因此可以省略。
android:label指定活动中的标题栏的内容。
需要注意的是,给主活动指定的label不仅会成为标题栏,而且还会成为Laucher中应用程序的名称。
标签,中的使这个活动成为这个程序的主活动。
如果一个程序没有主活动,那么一般这样的程序都是作为第三方服务供其他应用在内部进行调用的。

隐藏标题栏

只需要在setContentView()方法之前加一句:
requestWindowFeature(Window.FEATURE_NO_TITLE);

在活动中使用Toast

只需要在需要触发Toast的地方加上Toast.makeText方法就行。

Button button1 = (Button) findViewById(R.id.button_1);button1.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        Toast.makeText(            FirstActivity.this,             "You clicked Button 1",             Toast.LENGTH_SHORT         ).show();     }});

在活动中使用Menu

先在res中创建menu文件夹,创建一个main.xml布局文件,在XML文件中创建菜单布局。

        

Activity中重写onCreateOptionMenuonOptionItemSelected方法。

public boolean onCreateOptionMenu(Menu menu){    getMenuInflater().inflate(R.menu.main, menu);    return true;}public boolean onOptionItemSelected(MenuItem item){    switch (item.getItemId()) {        case R.id.add_item:            Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show();            break;        case R.id.remove_item:            Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show();            break;        default:            break;    }    return true;}

销毁一个活动

直接调用finish方法即可。

使用Intent

Intent可以在活动之间跳转。

使用显式Intent

新建一个layout布局文件,在其中创建第二个活动的布局。
AndroidManifest.xml中进行注册。只需要注册一个name即可。
在按钮的点击事件中添加代码:

public void onClick(View v) {    Intent intent = new Intent(        FirstActivity.this,           SecondActivity.class    );    startActivity(intent);}

构建一个Intent实例,传入FirstActivity.this作为上下文,传入SecondActivity.class作为活动目标。然后通过startActivity方法来执行这个Intent

使用隐式Intent

隐式方法不明确支出想要启动哪一个活动,而是指定了一系列抽象的actioncategory等信息,由系统分析调用哪个活动。
首先在AndroidManifest.xml中配置

        

这个action标签指明了当前活动可以响应com.example.activity.test.ACTION_START这个actioncategory标签中包含一些附加信息,更精确地指明了当前活动能够相应的Intent中可能包含category。这两个属性同时匹配时才能相应该Intent
现在改变一下按钮的点击事件。

public void onClick(View v) {    Intent intent = new Intent(        "com.example.activity.test.ACTION_START"    );    startActivity(intent);}

新的Intent构造方法传入了一个action字符串,可以直接相应。
这里没有设定category,因为在注册表中注册的是DEFAULT默认,会自动添加到Intent
如果我们给Intent实例添加一个categoryintent.addCategory("com.example.activitytest.MY_CATEGORY");
这样就只能匹配特定的category。同时,给注册表中再添加一个相同的category,这样就能正常运行了。

更多隐式Intent的用法

隐式Intent不仅可以启动自己程序的活动,还可以启动其他应用程序的活动,这使得Android多个应用程序之间的功能共享成为可能。
下面演示用隐式Intent打开系统浏览器。

public void onClick(View v) {    Intent intent = new Intent(        Intent.ACTION_VIEW    );    intent.setData(Uri.parse(        "http://wzhzzmzzzy.farbox.com"    ));    startActivity(intent);}

这里指定actionIntent.ACTION_VIEW,这是一个Android系统内置的动作,常量值为android.intent.action.VIEW,然后通过Url.parse方法,解析网址成一个Url对象,调用setDate将其传递进去。

标签

setData方法可以接受一个Uri对象,,指定当前Intent正在操作的数据。通常数据都是以字符串的形式传入到Uri.parse方法中解析产生。
与之对应,我们可以在标签中再配置一个标签,用于更加精确地指定当前活动能够响应什么类型的数据。下面是标签中可以配置的内容:

android:scheme //用于指定数据的协议部分,如httpandroid:host//用于指定数据的主机名部分,如www.baidu.comandroid:port//用于指定数据的端口部分,一般跟随在主机名后android:path//用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容android:mimeType//用于指定可以处理的数据类型,允许使用通配符的方式进行指定

只有标签中指定的内容和Intent中携带的Data完全一致,当前活动才能相应。只要设置android:schemehttp,就可以相应所有的http协议的Intent了。

向下一个活动传递数据

通过putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent中,启动了另一个活动之后,只需要把这些数据再从Intent中取出就可以了。比如说FirstActivity中有一个字符串,现在想把它传递到下一个活动当中:

String s = "Hello SecondActivity";Intent intent = new Intent(    FirstActivity.this,     SecondActivity.class);intent.putExtra("extra_data", s);

然后再SecondActivity中取出数据:

Intent i = getIntent();String s = i.getStringExtra("extra_data");Log.d("SecondActivity", s);

首先通过getIntent方法获取到用于启动SecondActivityIntent,然后调用getStringExtra方法,传入相应的键值,就可以得到相应的数据了。如果传递int就用getIntExtra方法, 布尔值等以此类推。

返回数据给上一个活动

Activity中有startActivityFroResult方法,也是用于启动活动的,但是这个方法期望在活动销毁时返回一个结果给上一个活动。
该方法接受两个参数,第一个参数的Intent,第二个参数是请求码,用于在之后的回调中判断数据来源。

Intent intent = new Intent(    SecondActivity.this, ThirdActivity.class);startActivityForResult(intent, 1);
Button button3 = (Button) findViewById(R.id.button_3);button3.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        Intent intent = new Intent();        intent.putExtra(            "data_return",             "Hello FirstActivity");        setResult(RESULT_OK, intent);        finish();    }});

在活动中构建一个Intent用于传递数据。要传递的数据存放在Intent中,然后调用了setResult方法,这个方法专用于向上一个活动返回数据。
setResult方法有两个参数,第一个用于向上一个活动返回处理结果,一般只用RESULT_OK或者RESULT_CANCELED这两个值,第二个参数将带有数据的Intent传递回去。
由于我们使用startActivityForResult方法,在下一个活动销毁之后会回调上一个活动的onActivityResult方法,因此需要在FirstActivity中重写来得到返回的数据。
onActivityResult方法有三个参数,第一个参数请求码requestCode,第二个参数是返回数据时传入的处理结果resultCode,第三个是携带着返回数据的Intent data
因为一个活动中可能调用startActivityForResult启动很多不同的活动,每个活动返回的数据都会回调,因此需要检查处理结果resultCode来判断数据来源,确定数据是从SecondActivity返回的之后,我们再通过resultCode的值来判断处理结果是否成功。最后从data中取值并且打印出来。
但是还有一个问题!如果通过Back键来返回,那数据怎么带回来呢?这个时候需要重写一下onBackPressed方法。

@Overridepublic void onBackPressed(){    Intent intent = new Intent();    intent.putExtra("data_return", "Hello FirstActivity");    setResult(RESULT_OK, intent);    finish();}

活动的生命周期

返回栈

Android中的活动是可以层叠的。每创建一个新活动,就会覆盖在原活动之上,点击Back键就会销毁最上面的活动,下面的一个活动就会重新显示出来。
Android是使用任务�(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。每启动一个新活动,就会入栈,每当按下Back或者调用finish(),就会弹栈。每个引用程序都会有自己的返回栈。

活动状态

活动有四种状态:运行、暂停、停止、销毁。
在栈顶时运行、屏幕上可见时暂停、不再处于栈顶时停止、弹栈后销毁。

活动生存期

onCreate() //活动第一次创建时会调用onStart()  //活动由不可见变为可见是调用onResume() //活动准备好与用户交互时调用,此时活动位于栈顶onPause()  //在系统准备去启动或者恢复另一个活动时调用,通常会释放一些占用CPU的数据,保存一些关键数据onStop()   //活动完全不可见时调用,如果新活动不是对话框式则调用onStop,否则调用onPauseonDestroy()//活动被销毁之前调用,之后活动将变为销毁状态onRestart()//活动由停止变为运行之前调用

活动被回收了怎么办

如果活动被回收了,而弹栈之后到达了,就会再一次调用活动的onCreate方法,唯一的问题是活动中暂存的临时数据都丢失了。Activity中提供了一个onSaveInstanceState的回调方法,这个方法会保证一定在活动被回收之前调用,因此可以通过这个方法来解决活动被回收时临时数据得不到保存的问题。
onSaveInstanceState方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据。每个方法需要传入两个参数,一个是键,一个是真正要保存的内容。

@Overrideprotected void onSaveInstanceState(Bundle outState){    super.onSaveInstanceState(outState);      String tempData = "Somethin";      outState.putString("data_key", tempData);}

数据保存之后,onCreate方法中的Bundle参数就会获得这些数据。只需要再次取出即可。

if (savedInstanceState != null){      String tempData =         savedInstanceState.getString("data_key");    Log.d(TAG, tempData);}

活动的启动模式

启动模式有四种,standardsingleTopsingleTasksingleInstance。在AndroidManifest.xml中通过给标签指定android:launchMode属性来选择启动模式。

standard

standard是活动默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式。在standard模式加,每当启动一个新的活动,就会在返回栈中入栈,并且处于栈顶的位置。对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。

singleTop

singleTop模式下,如果启动活动时发现返回栈栈顶已经是这个活动,则认为可以直接使用它,不会创建新的实例。

singleTask

singleTop模式可以很好地解决重复创建栈顶活动的问题,但是如果该活动没有处于栈顶位置,还是可能会创建多个活动实例。在singleTask下,每次启动该活动室,系统首先会在返回栈中检查是否存在该活动的实例。如果发现已经存在则直接使用该实例,并把在这个活动之上的活动统统出栈,如果没有就创建新的实例。

singleInstance

这个模式算是四种启动模式中最特殊也最复杂的一个了。不同于以上三种,在singleInstance模式下,活动会启用一个新的返回栈来管理(如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。举个例子,假设程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,就可以用singleInstance模式创建一个单独的返回栈来管理这个活动,可以让任意应用程序来调用。

活动的最佳实践

了解当前是哪个活动

新建一个BaseActivity类,重写onCreate方法如下:

public class BaseActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        Log.d("BaseActivity", getClass().getSimpleName());    }}

然后让每个活动类都改为继承自BaseActivity,这样就可以在LogCat中看到当前类名。

随时随地退出程序

当在程序运行中的一个活动,要退出可能会需要按多次Back键,所以最好需要一个直接退出活动的方法。
新建一个ActivityCollector类作为活动管理器:

public class ActivityCollector {    public static List activities = new ArrayList();    public static void addActivity(Activity activity){        activities.add(activity);    }    public static void removeActivity(Activity activity){        activities.remove(activity);    }    public static void finishAll(){        for (Activity activity : activities)            if (!activity.isFinishing())                activity.finish();    }}

接下来修改BaseActivity

public class BaseActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        Log.d("BaseActivity", getClass().getSimpleName());        ActivityCollector.addActivity(this);    }    @Override    protected void onDestroy(){        super.onDestroy();        ActivityCollector.removeActivity(this);    }}

BaseActivityonCreate方法中调用ActivityCollectoraddActivity的方法,表明将当前正在创建的活动添加到活动管理器里,然后重写onDestroy方法,并且调用了ActivityCollectorremoveActivity方法,表明将一个马上要销毁的活动从活动管理器中移除。
以后,不管想在什么地方退出程序,只需要调用finishAll就可以了。

启动活动的最佳写法

之前启动的方法是构建一个新的Intent,然后调用startActivity或者startActivityForResult来启动活动。如果SecondActivity需要用到两个字符串参数,在启动时必须要传递,可能会写成下面这样:

Intent intent = new Intent(FirstActivity.this,                                SecondActivity.class);intent.putExtra("extra_data1", s1);intent.putExtra("extra_data2", s2);startActivity(intent);

这样虽然可以,但是在SecondActivity是一个黑盒子时,是会出现问题的。
可以修改SecondActivity的代码:

public static void actionStart(Context context, String s1, String s2){    Intent intent = new Intent(        context,         SecondActivity.class    );    intent.putExtra("extra_data1", s1);    intent.putExtra("extra_data2", s2);    context.startActivity(intent);}

这样写的好处是给以后需要启动SecondActivity的活动提供了一个actionStart方法来传入需要的参数,提升了代码的可读性和延续性。

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. Android自定义View(五)Canvas的常用方法
  4. 在android上用HttpURLConnection获取网页内容
  5. Android(安卓)WebView的loadData方法注意事项
  6. android检测新版本并下载安装的方法
  7. Android(安卓)蓝牙开发实例解析
  8. android事件分发机制(上)
  9. 深入理解onSaveInstanceState & onRestoreInstanceState 方法

随机推荐

  1. android 体系架构
  2. Android实例剖析
  3. Android(安卓)C/C++ 开发.
  4. 实现自己的Camera
  5. Android之UI学习篇三:TextVeiw单击文字链
  6. Android(安卓)中如何选择 compileSdkVers
  7. android permission权限与安全机制解析(下
  8. Android构建过程简述
  9. android eclipse 环境
  10. Android4.0:统一标准强行安装默认主题Holo