平台:
windows11
Android Studio 4.2.2
Build #AI-202.7660.26.42.7486908, built on June 24, 2021
Runtime version: 11.0.8+10-b944.6842174 amd64
VM: OpenJDK 64-Bit Server VM by N/A
Windows 10 10.0
GC: G1 Young Generation, G1 Old Generation
Memory: 4096M
Cores: 16
Registry: external.system.auto.import.disabled=true
Non-Bundled Plugins: com.intellij.ideolog, com.genymotion.idea, com.kite.intellij, org.jetbrains.kotlin
1.配置gradle,gradle的版本是越高越好。所以首先需要去获取gradle的最新版本,然后将他解压后放在一个比较好用的地方。
然后在Android studio中的
file----settings----Build Execution-Deployment----build tools ----Gradle
中设置,
上面的第一个框选择放入gradle的目录。
下面的适用于特定项目,对于任何一个项目,创建完毕即把 use gradle from 改为specific location 并选择gradle的目录是一个好习惯。可以减少下载错误,下载浪费,提高效率。
下载官方地址:Gradle | Installation
也可以问小伙伴要一份。
2.使用国内代理,用于下载依赖
在项目的build.gradle中添加,
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public'}
(超越图片权限)推荐把这个放在respositories的第一行,这样或许会优先使用阿里云的国内镜像源进行下载依赖。事实上,这样会极大的提高依赖下载速度,尤其是网络不稳定时。
3.创建可靠的调试环境。(参考)
事实上,调试的速度很大程度上也决定了你的开发速度。当具备可靠的调试环境时,开发速度也会提升不少。
(1)一个经过测试较为稳固的虚拟机创建方案是
按如图方式以此选择,紧接着按照默认创建一个虚拟机。注意不要频繁操作。
(2)使用Genymotion.创建虚拟机。
这个相对来说比较稳定,但是对于Api较高的android系统的支持不是很好,而且也会有不稳定的情况发生。
事实上,如果方法(1)的虚拟机足够稳定,那么就选用第一个就好了,使用感受比第二种的虚拟机好。
如果出现虚拟机连接失败等错误,建议重启电脑。一般可以连接成功。
如果是出现 wait all 。。。to come online,这句话,可以适当等个30s如果还不行就删掉虚拟机,重启然后再新建一个虚拟机。
4.查看异常
在运行了一个app时,可以打开下方菜单栏的run来查看app运行的log和异常代码位置。(这点在处理程序异常退出,或者异常卡住等时查看报错信息,同时程序代码中的log函数的输出也在这里。)
event log则是用来查看android studio的log。
5.简述Android的Activity和Fragment与UI
(1)Activity与UI
给Activity分配UI
MainActivity.java
package cn.basicconstruction.example;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setText("hello");
setContentView(textView);
Log.d("", "MMMMMMMMMM: "+textView);
setContentView(R.layout.activity_main);
}
}
run,可以看到程序正常运行,这也意味着,在运行时我们也可以通过函数调用来更改Activity的布局代码。事实上,我进行了尝试,成功了。这意味着setContentView这个函数,并不是在onCreate中能且仅能运行一次。而是可以运行多次。甚至可以取代多个Activity之间的跳转。但是这样也会带来空引用等问题。只能说是可以这么用,但是不推荐这么用。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setText("hello");
setContentView(textView);
Log.d("", "MMMMMMMMMM: "+textView);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
setContentView(R.layout.activity_main2);
}
});
}
注意,第一个布局里面有一个按钮。
注意:在应用中使用Activity时需要在配置清单文件AndroidManifest.xml中注册。在配置清单文件中的application分支下添加一个新的activity标签。activity标签包含一系列元数据属性,如label,icon,permission,theme等。
没有对应的activity标签的Activity不能使用----启动时系那个会触发异常。
如果使用ide创建项目,则会自动配置mainactivity的配置清单。
再新建activity时需要自己注册。
(1)(3)Activity的状态--简述
a,活动状态—可见且拥有焦点的前台Activity
b,暂停状态---Activity虽然可见,但是却没有获得焦点。
C,停止状态----Activity不可见,但还没从内存中移出。
D,不活动状态----Activity被杀死。
(1)(4)生命周期
-
onCreate
使用onCreate方法初始化Activity,初始化UI,如果Activity被运行时环境意外终止,onCreate方法将会传递一个Bundle对象,其中包括上次调用onSaveInstance方法保存的状态,当然这个保存状态的操作也可以用onRestoreIntstanceState来执行。
2.可见的生命周期
可见的生命周期发生在onStart和onPause两个处理程序之间。
onStop方法应该用于暂停或停止动画,线程,传感器,侦听器,GPS定位,计时器,Service或其他专门用于更新UI的进程。因为当UI不可见时,使用资源来更新UI没有任何价值。当UI再次可见时,我们可以使用onStart方法恢复或重新启动这些进程。
onRestart方法只有在第一次调用onStart的时候不被调用,之后每一次都会在onStart方法之前被调用。
3.活动的声明周期
活动的生命周期以onResume方法被调用开始,并在onPause方法被调用时结束。
活动的生命周期是指活动获得焦点到失去焦点的过程。
应尽量保持onPause和onResume方法中代码快速且轻量级,以确保应用在进入前台时马上响应。
如果系统确定可能需要恢复Activity的状态,那么再onPause调用之前立即调用onSavedInstanceState。这使得一个Activity的UI状态可以保存在Bundle,并进而传递给onCreate和onRestoreInstanceState.
使用onSavedInstanceState保存UI状态,可以确保Activity在下一次重新处于活动状态时能够呈现相同的UI。但有时系统也会决定不恢复当前状态,也会不调用onSavedInstanceState.
在 Android API 11后,onStop处理程序的完成标志着一个Activity不会在没有警告的情况下被终止。这使得我们应尽量的把耗时的操作转移到onStop方法中,使得onPause更加轻量。
MainActivity.java
package cn.basicconstruction.example;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//onCreate方法只在Activity的生命周期中被调用一次,因此应尽可能把耗时的初始化操作置于此。
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onRestart(){
super.onRestart();
//方法在第一次调用onStart的后时候不被调用,之后每一次都会在onStart方法之前被调用,可以用来实现仅当
//Activity在完整的生命周期内重新启动时才需要执行的特殊处理。
//在Activity进程进入可见状态时加载相应的变化。
}
@Override
protected void onStart() {
super.onStart();
//在可见的生命周期开始时调用
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
//调用Activity最后被Android运行时(ART)销毁,然后启动。
//而不是通过用户或程序操作(例如用户回击或调用finish()),
//那么该方法会在onStart()方法结束后被调用。
//从savedInstanceState中恢复UI的状态
//这个bundle实例还会被传送到onCreate方法中。
//那么该方法中onStart()方法结束后被调用。
}
@Override
protected void onResume(){
super.onResume();
//活动的生命周期开始时调用
//恢复Activity所需的任何暂停的UI状态
//但他们会在Activity处于不活动状态时暂停。
//而在此阶段,Activity处于活动状态。
//并接受来自用户操作的输入。
}
@Override
protected void onPause(){
super.onPause();
//活动的生命周期结束时调用
//当Activity不在处于前台活动状态时,就会挂起不需要的Ui更新,
//线程或CPU密集型操作。注意在多屏模式下,暂停的Activity可能仍然可见,因此应该继续所需的UI更新。
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
//保存到savedInstanceState这个Bundle实例中,传递给onCreate和onRestoreInstanceState方法
//在适当的时机被调用
}
@Override
protected void onStop(){
super.onStop();
//在可见的生命周期结束时调用
//当Activity彻底不可见时,挂起不需要的剩余UI更新,线程或相应的处理。保存好所有的状态更改
//因为Activity可能在onStop完成后的任何时候被终止
}
@Override
protected void onDestroy(){
super.onDestroy();
//有时在完整的生命周期结束时调用
//清理所有资源,包括结束线程,关闭数据库连接等。
}
}
(2)(1)Fragment和UI
Fragment使你能够将Activity划分为完全封装的可重用组件,每个组件都有自己的生命周期和状态。
每一个fragment都是一个独立的模块,Fragment可以包含UI也可以不包含,并且还可以在多个Activity中使用。封装了UI的fragment可以多种组合形式进行编排,以适应多窗格的UI,还可以在运行的Activity中执行添加,删除和交换等操作,以此帮助构建动态的用户界面。
在这里不在记叙Fragment的生命周期。
package cn.basicconstruction.example;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class ImgFragment extends Fragment {
public ImgFragment(){};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
return inflater.inflate(R.layout.fragment_img,container,false);
}
}
【1】获取父activity的组件引用。
@SuppressLint("SetTextI18n")
@Override
public void onStart(){
super.onStart();
TextView tv = (Objects.requireNonNull(ImgFragment.this.getActivity()).findViewById(R.id.lt));
tv.setText("hello world");
TextView tb = (Objects.requireNonNull(ImgFragment.this.getActivity()).findViewById(R.id.button));
tb.setText("hello world");
}
其中ImgFragment是该fragment的类。
【注意】
Fragment的创建生命周期发生在第一次调用onCreate方法和最后一次调用onDestroy方法之间。没有调用相应的onDestroy方法就终止进程的情况是很常见的,因此Fragment不能依赖于onDestroy事件的触发。
本来的用处:从父组件中分离该Fragment。
不可靠(不可依赖的情形):直接销毁Activity,直接终止APP。
【2】创建Fragment
和Activity相比,应该使用onCreate方法初始化Fragment,但是与Activity不同之处是,Fragment UI没有在onCreate方法中填充。
可以使用onCreateView方法初始化Fragment,膨胀UI并获取所包含的View的引用。
[3]Fragment manager
每一个Activity都有一个Fragment manager,用来管理它所包含的Fragment。在使用支持库时将使用getSupportFragmentManager方法来访问Fragemnt manager.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentManager主要用于父组件(Activity)获取fragment的组件,比如
View view = fragmentManager.findViewById(R.id....);
FragmentManager还通过FragmentTransaction对Fragment执行添加,删除,和替换等操作。
本来FragmentManager实际上是一个抽象类,其中的方法并没有完全实现,而支持库的工厂函数返回的实例实际上是一个实现过的FragmentManager对象。
【4】将Fragment添加到Activity中,
(1)适用于 使用Fragment定义一组基于不同屏幕大小的静态布局。也就是嵌入这个fragment,并不打算对fragment这种View其进行删除,添加等操作。
在Activity的XML布局文件中包括一个fragment标签.
比如:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/lt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Hello World!" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"
tools:layout_editor_absoluteX="148dp"
tools:layout_editor_absoluteY="240dp" />
<FrameLayout
android:id="@+id/frag"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<fragment android:name="cn.basicconstruction.example.ImgFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/f2" />
</LinearLayout>
橙红色部分,就添加了一个Fragment到Activity中,可以说是很轻便。
(2)通过容器来使用Fragment在这里可把FrameLayout看作是一个最基本的View控件,既可代表Button这样的简单组件,也可代表fragment这样的复合组件。
ViewGroup类也继承自View类,它支持添加子类视图。
ViewGroup也是View.
这里的FrameLayout也可替换为其他ViewGroup。比如:LinearLayout,RelativeLayout等。
如上方青色部分。
Massive
/1使用Fragment Transaction
Fragment Transaction用于添加,删除和替换Fragment。使用Fragment Transaction,可以使布局具有动态性,也就是说,他们将根据用户交互和应用状态进行调整和更改。
每个Fragment Transaction可以包含受支持操作的任意组合,包括添加,删除和替换Fragment等。
可以使用Fragment Transaction地beginTransaction方法创建新的Fragment Transaction。在设置要显示地动画以及适当地后退栈行为之前,可根据需要使用add,remove,和replace方法来修改布局。当准备执行更改时,需要调用commit方法以异步方式将事务添加到UI队列中,或者使用commitNow方法阻塞线程,直到事务完全完成。
FragmentTransaction ft = fragmentManager.beginTransaction()
/2添加,移除和替换Fragment
在添加新的UIfragment时,创建并将新的Fragment实例以及放入容器View传递给Fragment Transaction的add方法,(可选)可以指定标记(TAG),以便以后使用findViewByTag方法查找Fragment。
添加ADD
FragmentTransaction ft = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frxx,new frxxx(param1),TAG);
fragmentTransaction.commitNow();
移出REMOVE
Fragment fragment = fragmentManager.findViewByTag(TAG);
FragmetTransaction.remove(fragment);
fragmentTransaction.commitNow();
替换REPLACE
FragmentTransaction ft = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frxx,new frxxx(param2),TAG);
fragmentTransaction.commitNow();
/3 Fragment和配置更改与Bundle
简单来说就是为了避免添加多个Fragment,让我们再次看一看这个 add方法(见上)。每次添加的是一个frxxx(param1).可能会在状态改变时再次添加一个Fragment导致UI布局发生改变。
<
为了在配置更改过程中保持一致的UI状态,在屏幕方向更改或意外终止后创建Activity时,将自动恢复添加到UI中所有的Fragment。
如果在onCreate方法中向Activity布局填充Fragment,则必须检查这些Fragment此前是否已经添加,以避免重复创建多个副本。
可以通过在添加Fragment之前检查它们,或者通过检查savedInstanceState变量是否为null来重新启动Activity。
ImgFragment imgFragment;
if(savedInstanceState == null){
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.frag,new ImgFragment(),My_fragment);
ft.commitNow();
}
imgFragment = (ImgFragment)fragmentManager.findFragmentByTag(My_fragment);
>
/4通过Fragment Manager获取Fragment。
///1将fragment借助xml文件添加到Activity布局中。
MyFragment myFragment = (MyFragment)fragmentManager.findFragmentById(R.id.MyFragment);
实例:
<fragment android:name="cn.basicconstruction.example.ImgFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/f2" />
@Override
protected void onStart() {
super.onStart();
Log.d(tag, "onPause: Pause");
ImgFragment imgFragment = (ImgFragment)fragmentManager.findFragmentById(R.id.frag);
assert imgFragment != null;
imgFragment.t2.setText("@t2");
ImgFragment imgFragment2 = (ImgFragment)fragmentManager.findFragmentById(R.id.f2);
assert imgFragment2 != null;
imgFragment2.t2.setText("@t3");
//在可见的生命周期开始时调用
}
为什么放在这里?
这是因为Activity的onCreate早于内嵌Fragment的onCreateView所以如果写在Activity的onCreate会出现空引用现象。而恰好这样可以,这说明了学习生命周期的重要性。
///2使用Fragment Transaction添加一个Fragment,查找Fragment容器View的资源标识符,
MyFragment myFragment = (MyFragment)fragmentManager.findFragmentById(R.id.view_in_activity_fragment_view);
部分见上(代码)
<FrameLayout
android:id="@+id/frag"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
///3也可以使用findFragmentByTag方法。
MyFragment myFragment = (MyFragment)fragmentManager.findFragmentByTag(TAG);
尤其适用于不含UI的Fragment。
/5 要删除给定方向布局中的Fragment容器,只需要在布局定义中将visibility属性设置为gone即可。
<FrameLayout
android:id="@+id/frag"
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="wrap_content"/>
/6Activity与Fragment之间的通信。
Activity: MainActivity
Fragment: ImgFragment 实例 imgFragment
\\\context
在MainActivity.java中调用imgFragment.getContext()与在ImgFragment的onAttach(Context context)中传给这个函数的context是一个context也即父Activity的context。也与在Activity中调用
this是一样的。toString()均为:
cn.basicconstruction.example.MainActivity@69db4f(特定情况,实例)
\\\View
<1>获取父Activity组件引用
在Activity中可以使用(this.)findViewById(R.id.xxx)组件。
在Fragment中使用getActivity().findViewById(R.id.xxx)可以获取弗雷德组件。
<2>获取子Fragment组件引用
在Activity中使用fragmentManager.findFragmentById/Tag(xx).getView().findViewById(R.id.xxx)可以获取到Fragment(含UI)的组件的引用。
<备注如果出现失误,
这样用 ImgFragment imgFragment = fragmentManager.findFragmentById/Tag(xx);
Button bt = imgFragment.getView().findViewById(R.id.xxx);
>
在Fragment中在onCreateView中使用
View view = inflater.inflate(R.layout.fragment_ui,container,false);
Button bt = (Button)view.findViewById(R.id.xxx).
事实上,基于这个也可以使用this.getView().findViewById(R.id.xxx);
这个是由Fragment.getView().findViewById(R.id.xxx)获得启发。但是这个getView()获取需要在onCreateView()完成之后。可以在onStart等方法中使用。
可以获取到Fragment的组件的引用。在onCreateView()中使用this.getView().findViewById(xxx)会因为程序异常而导致空引用。空引用是指getView()获得的引用是空的,因为还没有初始化View,或者getView()函数依赖于onCreateView()返回的View。
last:
没有UI的Fragment。
因为Fragment没有UI,所以他不将于容器View相关联,于是就可以忽略掉R.id.xxx这个参数.[在这里拷贝之前的代码进行更改]
ImgFragment imgFragment;
if(savedInstanceState == null){
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(new ImgFragment(),My_fragment);
ft.commitNow();
}
imgFragment = (ImgFragment)fragmentManager.findFragmentByTag(My_fragment);
由于太长的文本会使得阅读和建立目录变得困难,故在这里分页。
参考:ISBN 978-7-302-53952-0 Android高级编程 Professional Android,Fourth Edition.