Android开发帮助技巧(适用于入门)(第一部分-高效地构建项目的准备工作和Activity与Fragment的交互介绍)

本文介绍了如何配置AndroidStudio的Gradle以使用最新版本并提高效率,设置国内代理以加速依赖下载,创建可靠的调试环境,包括虚拟机的配置和使用。此外,详细讲解了Activity的状态和生命周期,以及Fragment的使用和与UI的关系,强调了动态管理Fragment的方法和Activity与Fragment之间的通信。
摘要由CSDN通过智能技术生成

平台:

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)生命周期

  1. 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.
 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫叶kx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值