全局获取Context的技巧
活动本身就是一个Context对象。
class HttpUtil {
public static void sendHttpRequest(final String address, final HttpCallbackListener listener) {
...
if (!isNetworkAvailable()) {
//当检测到网络不存在的时候就给用户一个Toast提示
}
}
}
但在HttpUtil类中显然是获取不到Context对象的。想要快速解决问题,可以在sendHttpRequest()方法中添加一个Context参数。
class HttpUtil {
public static void sendHttpRequest(final Context context, final String address, final HttpCallbackListener listener) {
...
if (!isNetworkAvailable()) {
//当检测到网络不存在的时候就给用户一个Toast提示
Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
}
}
}
但这种解决方案实际上是推卸责任,将获取Context对象的任务转移给了sendHttpRequest()方法的调用方,至于调用方如何获得Context对象、能否获得Context对象,就撒手不管了。
Android提供了一个Application类,每当应用程序启动的时候,系统就会自动将这个类进行初始化。我们可以定制一个自己的Application类,以便于管理程序内一些全局的状态信息,比如说全局Context。
public class Myapplication extends Application {
private static Context context;
@Override
public void onCreate() {
context = getApplicationContext();
}
public static Context getContext() {
return context;
}
}
重写了父类的onCreate()方法,并通过调用getApplicationContext()方法得到了一个应用程序级别的Context,然后又提供了一个静态的getContext()方法,在这里将刚才获得的Context进行返回。
接下来需要告知系统,当程序启动的时候应该初始化MyApplication类,而不是默认的Application类。在AndroidManifest文件的<application>标签中进行指定即可。
<application
android:name="com.example.networktext.MyApplication"
...>
...
</ application>
注意,任何一个项目都只能配置一个Application。
至此实现了一种全局获取Context的机制,之后不管想在项目任何地方使用Context,只需要调用MyApplication.getContext()方法即可。
class HttpUtil {
public static void sendHttpRequest(final String address, final HttpCallbackListener listener) {
...
if (!isNetworkAvailable()) {
//当检测到网络不存在的时候就给用户一个Toast提示
//不再需要通过传参的方式来得到Context对象
//调用MyApplication.getContext()即可
Toast.makeText(MyApplication.getContext(), "network is unavailable", Toast.LENGTH_SHORT).show();
}
}
}
此时不再需要通过传参的方式来得到Context对象,调用MyApplication.getContext()即可。
使用Intent传递对象
Intent可以借助它启动活动、发送广播、启动服务等。在进行上述操作时,还可以在Intent中添加一些附加数据,以达到传值的效果。
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("string_data", "hello");
intent.putExtra("int_data", 100);
startActivity(intent);
调用了Intent的putExtra()方法来添加要传递的数据,之后在SecondActivity中就可以得到这些值。
getIntent().getStringExtra("string_data");
getIntent().getIntExtra("int_data", 0);
使用Intent传递对象通常有两种实现方式:Serializable和Parcelable。
Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
实现序列化的方法很简单,只需要让一个类实现Serializable接口即可。
public class Person implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这里让Person类实现了Serializable接口。
Person person = new Person();
person.setName("Tom");
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("person_data", person);
startActivity(intent);
由于Person类实现了Serializable接口,所以才可以这样写。
接下来在SecondActivity中获取这个对象也很简单。
Person person = (Person) getIntent().getSerializableExtra("person_data");
Lambda表达式
Lambda表达式本质上是一种匿名方法,既没有方法名,也即没有访问修饰符和返回值类型,使用它来编写代码将会更加简洁、易读。
如果想在Android项目中使用Lambda表达式或者Java8的特性,需要在app/build.gradle中添加如下配置:
defaultConfig {
...
jackOptions.enabled = true;
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8;
targetCompatibility JavaVersion.VERSION_1_8;
}
传统情况下开启一个子线程的写法:
new Thread(new Runnable() {
@Override
public void run() {
//具体逻辑
}
}).start();
使用Lambda表达式的写法:
new Thread(() -> {
//具体逻辑
}).start();
为什么可以这么写呢?
因为Thread类的构造函数接受的参数是一个Runnable接口,而Runnable接口中只有一个待实现的方法。
public interface Runnable {
void run();
}
凡是这种只有一个待实现方法的接口,都可以使用Lambda表达式的写法。
通常创建一个类似于上述接口的匿名类实现需要这样写法:
Runnable runnable = new Runnable() {
@Override
public void run() {
//具体实现
}
};
有了Lambda表达式后可以这样写:
Runnable runnable = () -> {
//具体实现
};
新建一个MyListener接口:
public interface MyListener {
String doSth(String a, int b);
}
使用Lambda表达式创建MyListener接口的匿名实现写法:
MyListener listener = (String a, int b) -> {
String result = a + b;
return result;
}
java还会根据上下文自动推断出Lambda表达式中的参数类型,可以简化为:
MyListener listener = (a, b) -> {
String result = a + b;
return result;
}
一个具体的例子:
public void hello(MyListener listener) {
String a = "hello lambda";
int b = 1024;
String result = listener.doSth(a, b);
Log.d("TAG", result);
}
在调用hello()方法时可以这样写:
hello((a, b) -> {
String result = a + b;
return result;
});
处理点击事件时也可以使用Lambda表达式:
//不实用Lambda表达式
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//处理点击事件
}
});
//使用Lambda表达式
button.setOnClickListener((v) -> {
//处理点击事件
});