Android应用层开发碎片知识
startActivityForResult
应用场景
比如从AActivity跳转到BActivity,然后在BActivity中做一系列操作,然后在BActivity关闭时候需要把一些数据再回传给AActivity,或者当BActivity关闭后,需要让AActivity的界面或者数据发生一些变化。
示例代码
startActivityForResult(
new Intent(MainActivity.this, LoginActivity.class),
Constants.RequestCode.REQUEST_CODE_LOGIN);
以上代码表示从MainActivity跳转至LoginActivity,当LoginActivity关闭后将Constants.RequestCode.REQUEST_CODE_LOGIN
传回给MainActivity。
Rxjava
Disposable类
- dispose():主动解除订阅
- isDisposed():查询是否解除订阅 true 代表 已经解除订阅
示例代码
// 创建一个Disposable
Disposable mDisposable = Observable
// 每间隔延迟1s发送一次数据
.interval(0, 1L, TimeUnit.SECONDS)
// 将发送的数据按map中的计算式计算后返回
.map(new Function<Long, Long>() {
@Override
public Long apply(Long countDownSecond) {
return retrySecond - countDownSecond;
}
})
// 在io线程中发送消息
.subscribeOn(Schedulers.io())
// 在主线程中接收消息
.observeOn(AndroidSchedulers.mainThread())
// 在onNext()每次发送完消息后的操作
.doOnNext(new Consumer<Long>() {
@Override
public void accept(Long aLong) {
mBtnConfirm.setVisibility(View.GONE);
mBtnConfirm.setFocusable(false);
mBtnCancel.setText(getStrings(R.string.dialog_cancel));
mBtnCancel.requestFocus();
}
})
// 接收消息
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long currSecond) {
...
});
// 判断是否解除订阅
if(!mDisposable.isDisposable()){
mDisposable.disposable(); // 如若没有解除订阅则解除订阅
}
CompositeDisposable
一个disposable的容器,可以容纳多个disposable,添加和去除的复杂度为O(1)。
如果这个CompositeDisposable容器已经是处于dispose的状态,那么所有加进来的disposable都会被自动切断。
用CompositeDisposable来管理订阅事件disposable,然后在acivity销毁的时候,调用compositeDisposable.dispose()就可以切断所有订阅事件,防止内存泄漏。
示例代码
CompositeDisposable mDisposable = new CompositeDisposable();
// 添加disposable
mDisposable.add(disposable);
// 移除一个disposable
mDisposable.remove(disposable);
// 移除所有的disposable
mDisposable.clear();
DialogFragment
调用show()方法即可显示dialog,调用dismiss()方法即可取消dialog的显示。
基类 BaseDialogFragment
一般先写一个基类继承于Dialogfragment,再由具体的业务需求创建具体的DialogFragment继承基类。
基类中一般需要写以下几个方法,onCreateView()
创建显示dialog所在的view;onCreateDialog()
创建自定义的dialog;onViewCreated()
依据自定义的xml创建view。
示例代码如下:
public abstract class BaseDialogFragment extends DialogFragment {
protected BaseActivity mActivity;
private Unbinder mUnBinder;
private View mRootView;
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof BaseActivity) {
this.mActivity = (BaseActivity) context;
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = inflater.inflate(getLayoutId(), container, false);
mUnBinder = ButterKnife.bind(this, mRootView);
return mRootView;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
RelativeLayout root = new RelativeLayout(getActivity());
root.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
Dialog dialog = new Dialog(getContext());
dialog.setCancelable(true);
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
return onKeyListener(dialog, keyCode, event);
}
});
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(root);
dialog.getWindow().setLayout(resizeDialogWidth(), ViewGroup.LayoutParams.WRAP_CONTENT);
return dialog;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
mRootView.requestFocus();
setup(view);
super.onViewCreated(view, savedInstanceState);
}
@Override
public void show(FragmentManager manager, String tag) {
// 开启Fragment事务
FragmentTransaction transaction = manager.beginTransaction();
// 依据Tag获取Fragment
Fragment fragment = manager.findFragmentByTag(tag);
if (fragment != null) {
/*
Fragment被remove后,Fragment的生命周期会一直执行完onDetach,之后Fragment的实例也会从FragmentManager中移除。
*/
transaction.remove(fragment);
}
/*
将此事务添加到后台堆栈。这意味着该事务被提交后将会被记住后,回退操作后,事务会从堆栈中弹出。*/
transaction.addToBackStack(null);
show(transaction, tag);
}
@Override
public void onDestroyView() {
if (mUnBinder != null) mUnBinder.unbind();
super.onDestroyView();
}
@Override
public void onDetach() {
mActivity = null;
super.onDetach();
}
/**
* 监听响应事件
*/
protected boolean onKeyListener(DialogInterface dialog, int keyCode, KeyEvent event) {
return false;
}
protected abstract int getLayoutId();
/**
* 对话框创建后,在该方法修改对话框布局的某些view
*/
protected abstract void setup(View view);
}
transaction.addToBackStack(null);
- 第1次按下手机的back键,其实是回退了之前的add操作,如果再FragmentManager中没有add任何Fragment,程序没有退出而是变成了白板。
- 第2次按下手机的back键,因为当前回退栈已空,addToBackStack中添加的是null,程序就直接退出了。
Handling Lifecycles
Handling Lifecycles包含的主要内容:
1.Lifecycle
2.LifecycleObserver
3.LifecycleOwner
LifecycleObserver
简单介绍
- 定义具有Android生命周期的对象
- v4包的Fragment与FragmentActivity类实现了LifecycleOwner接口,通过接口里面的getLifecycle()方法获取Lifecycle对象。
- 我们可以在自己类里面实现LifecycleOwner接口。
- 包含事件Events与状态States
示例代码
定义一个实现Lifecycles接口的基类BasePresenter
public class BasePresenter<T> implements LifecycleObserver {
private CompositeDisposable mDisposable = new CompositeDisposable();
protected T mView;
public BasePresenter(T view) {
this.mView = view;
}
protected void addObserver(@NonNull Disposable disposable) {
mDisposable.add(disposable);
}
protected void removeObserver(@NonNull Disposable disposable) {
mDisposable.remove(disposable);
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
protected void release() {
mDisposable.clear();
mView = null;
}
}
定义一个具体的AuthPresenter,继承BasePresenter,用注解的方式表明那个方法在Activity不同的生命周期运行,代码如下:
public class AuthPresenter extends BasePresenter{
....
public AuthPresenter(AuthContract.View view) {
super(view);
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void handleMultiError() {
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
Log.i(TAG, throwable.getMessage());
}
});
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
@Override
public void registerNetwork() {
Context context = (Context) mView;
mNetworkObserver = new NetworkObserver(context);
mNetworkObserver.registerNetworkReceiver();
mNetworkObserver.setNetworkListener(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
@Override
public void unregisterNetwork() {
if (mNetworkObserver != null) {
mNetworkObserver.unregisterNetworkReceiver();
}
}
.....
}
在需要监听它生命周期的activity中加入getLifecycle().addObserver(new AuthPresenter()),示例代码如下:
public class MainActivity extends BaseActivity{
private AuthPresenter mPresenter;
@Override
protected void setup() {
mPresenter = new AuthPresenter(this);
getLifecycle().addObserver(mPresenter);
}
....
}
LifecycleOwner
基类实现implements LifecycleOwner接口,然后实现getLifecycle,当然LifecycleRegistry这个类是官方提供的默认事件注册类,最后在你想要监听的生命周期中通知mLifecycleRegistry.markState,生命周期改变。
示例代码如下:
public class MyActivity extends Activity implements LifecycleOwner {
private LifecycleRegistry mLifecycleRegistry;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.markState(Lifecycle.State.CREATED);
}
@Override
public void onStart() {
super.onStart();
mLifecycleRegistry.markState(Lifecycle.State.STARTED);
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
android应用程序中启动另一个应用程序
new Intent(xxxActivity.this, xxxActivity.class)
// 在Activity中执行
startActivity(new Intent(getApplication(),xxxActivity.class));
//在类中执行
if(getContext() != null){
startActivity(new Intent(getContext().getApplicationContext(),
xxxActivity.class));
}
intent.setComponent(String …str)
不仅可以启动自定义的应用程序,也可启动系统的应用程序。new Component的构造法中第一个参数是启动应用的包名,第二个参数是启动应用的类名。
Intent intent = new Intent();
intent.setComponent(new Component("com.android.settings", "com.android.settings.Settings"));
// 在Activity中执行
startActivity(intent);
// 如若在类中执行
if(getContext() != null){
getContext().startActivity(intent);
}
intent.setFlags()
示例代码:
Intent intent = new Intent();
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
以下是各个参数的具体含义
FLAG_ACTIVITY_NEW_TASK
应用场景:
从非Activity的非正常途径启动一个Activity。
工作流程:
如现在栈1的情况是:A B C。C通过intent跳转到D,并且这个intent添加了FLAG_ACTIVITY_NEW_TASK标记,如果D这个Activity在Manifest.xml中的声明中添加了Task affinity,系统首先会查找有没有和D的Task affinity相同的task栈存在,如果有存在,将D压入那个栈,如果不存在则会新建一个D的affinity的栈将其压入。
因为activity要存在于activity的栈中,而非activity的途径启动activity时必然不存在一个activity的栈,所以要新起一个栈装入启动的activity
FLAG_ACTIVITY_CLEAR_TOP
跳转到的activity若已在栈中存在,则将其上的activity都销掉。
例如现在的栈情况为:A B C D 。D此时通过intent跳转到B,如果这个intent添加FLAG_ACTIVITY_CLEAR_TOP标记,则栈情况变为:A B。
FLAG_ACTIVITY_NO_HISTORY
跳转到的activity不压在栈中。
例如现在栈情况为:A B C。C通过intent跳转到D,这个intent添加FLAG_ACTIVITY_NO_HISTORY标志,则此时界面显示D的内容,但是它并不会压入栈中。如果按返回键,返回到C,栈的情况还是:A B C。
FLAG_ACTIVITY_SINGLE_TOP
和Activity的Launch mode的singleTop类似。目标activity已在栈顶则跳转过去,不在栈顶则在栈顶新建activity。
Android Studio怎样设置SDK的路径
1. 用File修改
打开Android studio,点击“File”菜单下的“Other Settings”,接着点击“Default Project Structure”选项。
这时就会看到SDK Location,点击图示第二个红色区域的图标,就可以修改默认的AndroidSDK路径。
2. 启动Android Studio用Config修改
选择“Configure”,选择"Project Defaults",弹出设置默认工程的SDK路径
3. 修改路径时会出现的错误
- SDK文件夹下面要有platforms文件夹,不然出现Android Studio报错:SDK does not contain any platforms.
- SDK文件夹所在目录不能有空格,否则会出现报错,Android SDK location should not contain whitespace, as this can cause problems with the NDK tools.
A system image must be selected to continue
在启动项目建立虚拟设备时报错,表示系统图像不连续,下载Recommended列中的一些系统图片即可,如图中的Q,Pie,Oreo等。
导入com.android.support:percent:24.2.1包报错
**报错信息:**在app文件夹下build.gradle导入代码
depedencies{
....
imlementation 'com.android.support:percent:24.2.1'
.....
}
Sync后显示错误
All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 26.0.0-alpha1, 24.2.1. Examples include com.android.support:animated-vector-drawable:26.0.0-alpha1 and com.android.support:percent:24.2.1 less... (Ctrl+F1)
There are some combinations of libraries, or tools and libraries, that are incompatible, or can lead to bugs. One such incompatibility is compiling with a version
问题的原因
简单来说就是所有com.android支持库必须使用完全相同的版本规范,混合版本可能导致运行时崩溃。现在对应的Android SDK版本过高,需要下载更低一版的SDK才能兼容com.android.support:percent:24.2.1
有一些库、工具和库的组合是不兼容的,或者可能导致bug。
解决办法
找到android SDK的文件夹I:\AndroidSDk\extras\android\m2repository\com\android\support\percent
在这里就能看到各种版本的percent,选择合适的版本进行导入。
如果找不到这个文件夹,在Android Studio中的file->setting->System Settings->Android SDK,选择下载较为常用的sdk4,5,6,7版本,再来导入此包。
read failed: EBADF
**具体报错信息:**java.io.IOException: read failed: EBADF (Bad file number)。
**报错原因:**这是由于在java中执行命令行命令后没有写入\n,导致读取命令行执行结果时报错。
解决示例代码如下:
String command = "ping baidu.com";
Process p = Runtime.getRuntime().exec("sh"); // 获取系统权限
DataOutputStream dos = new DataOutputStream(p.getOutputStream());
dos.write(command.getBytes());
dos.writeBytes("\n");
dos.writeBytes("exit\n");
dos.flush();
int status = p.waitFor(); // 命令执行结果
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); // 命令执行输出结果
String line = null;
// 打印输出结果
while ((line = br.readLine()) != null) {
Log.i(TAG, "ping: " + line);
}