安卓开发(3)—1— Activity

3.1 Activity是什么:

在前面安卓概述中有提到,Activity是Android开发中的四大组件,所有在app里可以看到的东西都是Activity里面的,Activity主要是用来和用户直接进行交互的。

3.2 Activity的基本用法

最开始创建的HelloAndroid采用的是IDE自带的MainActivy,这次直接创建一个什么都没有的Android项目来方便学习:

其它的配置参考:https://www.cnblogs.com/Sna1lGo/p/14823681.html 该博客。

3.2.1 手动创建Activity

采用了Empty Activity创建项目后,app/src/main/java/包名/ 文件夹是空的目录:

所有就需要我们手动来添加Activity组件,右键包名,新建一个Empty Activity:

勾选Generate Layout File会自动为该Activity创建一个对应的布局文件。勾选Launcher Activity表示会为项目开启向下兼容旧版系统的模式,这个需要勾上不然兼容不了。这里为了学习,所以就不勾选Generate a Layout File ,自己手动创建布局文件。

在Android的项目中任何一个Activity文件都应该重写 onCreate函数,默认创建生成的onCreate函数很简单,就是调用了父类的onCreate函数而已。

3.2.2 创建和加载布局文件

Android程序讲究的是逻辑和视图分离,最好每一个Activity都有一个布局文件对应,布局文件就是资源文件里面用来显示内容的文件。

手动创建一个布局文件:右键app/src/main/res目录 选择New然后选择目录,先创建一个名叫layout的目录,然后再右键layout目录,创建一个layout xml File文件,将其按下图配置:

该layout文件可以查看多种格式,Code就是XML源代码模式,Split就是xml和可视化模式一样一半,Design就是可视化设计模式。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

</LinearLayout>

现在通过XML代码模式添加一个Button控件给布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <Button
      android:id="@+id/button1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Button 1"
      />
</LinearLayout>

可以通过旁边的desigh看到预览视角,添加了一个名为Button 1的按钮,接下来讲一下这段xml代码:

    <Button
      android:id="@+id/button1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Button 1"
      />
     
第一个:android:id="@+id/button1"
  @+id 这种用法比较少见,但是先不看加号 @id/button1不就是xml中引用资源的用法吗,只不过把string换成了id而已。
  这里的@+id就是定义一个id资源的用法,如果要定义一个id资源就需要采用 @+id/id_name这种用法。
 
第二个:android:layout_width="match_parent"
这里指定了布局文件的宽度,match_parent表示和父类的宽度一样。(宽度也就是横着的长度)

第三个:android:layout_height="wrap_content"
指定了布局文件的高度,wrap_content表明和父类的高度一样。(高度也就是竖着的长度)

第四个:android:text="Button 1"
指定了布局文件的文字内容。

Activity文件创建了,layout资源布局文件也创建了,接下来要做的就是把Activity和layout布局文件结合在一起:

        setContentView(R.layout.first_layout)
      这里调用了一个setContentView函数,来给该Activity加载一个布局文件,而setContentView一般的调用是给它传一个布局文件的id。
      其中安卓(1)里面讲了在Android项目中调用资源的方式:
      可以看到这里定义了一个应用程序名字的字符串,有两种方式可以拿来引用它:

1:在代码里面通过R.string.app_name可以获得该字符串的引用

2:在X M L中通过 @string/app_name可以获得该字符串的引用

其中的string部分是可以替换的,如果用的是图片资源就可以替换成drawable,如果是应用图标就可以替换成mipmap,布局文件就可以替换成layout
这里因为我们在res资源文件中有定义layout下的first_layout文件,所以就可以直接调用了。

3.2.3 在AndroidManifest文件中注册

所有的Activity组件都需要在AndroidMainifest文件中注册才能生效,实际上这里通过前面的流程,FirstActivity已经被注册了:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.helloworld3">

  <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:supportsRtl="true"
      android:theme="@style/Theme.HelloWorld3">
      <activity android:name=".FirstActivity"></activity>
  </application>

</manifest>

当自动创建组件的时候Android Studio就会自动添加AndroidManifest.xml文件,来防止程序允许崩溃,也是AS的一种人性化。

在<activity>标签中,使用了android:name来指定具体注册哪一个Activity,那么这里的.FirstActivity是什么呢,其实就是com.example.helloworld3.FirstActivity的缩写,就是com.example.hellworld3这个项目下的包名的Activity组件的名字:

其实这也是因为在该AndroidManifest.xml文件中前面的包(package)指定了是com.example.helloworld3,所以后面才可以这样写。

这样注册了Activity后还不行,因为还需要指定主Activity,就好比在C语言中指定main函数一样。要指定主Activity直接在AndroidMainifest中的<activity>标签中添加<intent-filter>标签就好了,并在该intent-filter标签中添加两行代码:<action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER" /> 就好了。还可以添加android:label来指定Activity标题栏中的内容。需要注意的是,给主Activity指定label不仅会成为标题栏中的内容,还会成为启动器(launcher)中应用程序显示的内容。

修改后的AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.helloworld3">

  <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:supportsRtl="true"
      android:theme="@style/Theme.HelloWorld3">
      <activity android:name=".FirstActivity"
          android:label="This is FirstActivity">
          <intent-filter>
              <action android:name="android.intent.action.MAIN"/>
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>


      </activity>
  </application>

</manifest>

这样该Activity就是这个程序的主Activity,点击打开APP时就是首先打开该Activity就和main函数一样,启动C程序首先启动main函数。

这样就实现了一个简单的Activity了:

总结如何创建Activity

Android项目讲究的是将逻辑和视图分离,所以要创建一个Activity不仅需要添加代码逻辑,还需要添加布局资源文,在 app/src/main/java/包名 目录下新建Activity代码逻辑,然后再在layout中添加Activity布局资源,最后再再AndroidManifest中检查是否有注册该Activity(一般都会自动注册)。要使用布局文件的什么内容就在在 app/src/main/java/包名 目录下新建Activity代码逻辑中使用,要让Activity展示什么内容就在Activity的资源布局文件的XML中修改。

3.2.4 在Activity中使用Toast

Toast是Android提供的一种提醒方式,用来在程序中给用户通知,在一段时间后会自动消失,且不会占用屏幕任何资源。

要创建Toast,首先需要定义一个弹出Toast的触发点,正好我们刚刚设计的Activity有一个button按钮,就让这个按钮的点击事件作为弹出Toast的出发点。在该Activity的onCreate中添加以下代码:

var button1: Button = findViewById(R.id.button1)
button1.setOnClickListener {
Toast.makeText(this,"You clicked Button 1",Toast.LENGTH_SHORT).show()
  }
var button1: Button = findViewById(R.id.button1)
//通过findViewById该API函数来获取在布局文件中定义的元素
//这里通过前面在定义布局文件中定义的ID来引入获取得布局文件中的按钮的实例 button1就是对应的button实例
//findViewById函数返回的是一个继承自View的泛型对象,所以kotlin没有办法自动推导它是Button还是其它控件
//所以需要显示地将button1这个变量声明称Button类型。
    button1.setOnClickListener {
Toast.makeText(this,"You clicked Button 1",Toast.LENGTH_SHORT).show()
  }
//调用setOnClickListener()方法给这个button按钮注册一个监听器,当被OnClick(被点击)的时候就会启动
//该监听器中使用了Toast.makeText()函数,Toast刚刚介绍过了,就是在APP中弹出内容的一个类
//然后该makeText()函数就是给该Toast修改内容,然后.show()函数,就是展示该Toast
//makeText()中有三个参数,第一个参数要传的内容是一个context,由于Activity本身也是一个Context对象
//这里可以直接将该Activity传进去,第二个参数是Toast显示的文本内容,第三个参数是Toast显示的时长
//第三个参数有两个宏定义可以选:Toast.LENGTH_SHORT和Toast.LENGTH_LONG

3.2.5 在Activity中使用Menu

菜单这个内容也是一个很常见的内容。

首先在res目录下新建一个menu文件夹,来存放菜单资源。接着创建一个名为main的Menu源代码文件:

然后在该新建的main.xml菜单源文件中添加以下代码:

    <item
      android:id="@+id/add_item"
      android:title="Add"/>
  <item
      android:id="@+id/remove_item"
      android:title="Remove"/>

这里创建了两个菜单项,其中<item>这个标签是用来创建具体的某一个菜单项,然后通过android:id来给该菜单项指定唯一的一个标识符,通过android:title来给该菜单项指定名称。

然后,还需要在Activity中重写onCreateOptionsMenu()该函数,因为该函数涉及菜单和Activity的联系:

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
      menuInflater.inflate(R.menu.main,menu);
      return true
  }

在讲解这段代码的时候,需要先讲解一个关于Kotlin语法糖的知识。Java Bean是一个很简单的类:

public class Book
{
private int pages;

public int getPages()
{
return pages;
}
public void setPages(int pages)
{
this.pages = pages
}
}

在Kotlin中调用该语法结构的Java代码时有一种非常简便的办法:

val book = Book()
book.pages = 500
val bookpage = book.pages

看起来是在瞎JB写,但是其实它是在后面自动调用了Book类的getPages和setPages函数。

这样类比到刚刚的Menu代码里面:

 menuInflater.inflate(R.menu.main,menu)
//这里实际上就是调用了getMenuInflater()方法得到了menuInflater对象,再调用它的inflate方法
//inflate方法有两个参数:第一个参数表明通过哪一个Menu资源文件来创建菜单
//第二个参数用来指定菜单项添加到哪一个Menu对象中,这里使用该Activity中重写的onCreateOptionsMenu
//传入的menu参数,表示添加到该Activity默认的菜单中
//如果该函数返回的是true表明会将新建的菜单显示出来
//如果返回的是false表明不会将新建的菜单显示出来

当然光显示出来是不够的,还需要给菜单添加响应,这样才可以完美配合。在Activity中重写onOptionsItemSelected()方法:

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
      when(item.itemId)
      {
          R.id.add_item -> Toast.makeText(this,"You Clicked Add",Toast.LENGTH_LONG).show()
          R.id.remove_item -> Toast.makeText(this,"You Clicked Remove",Toast.LENGTH_LONG).show()
      }

      return true
  }

这样生成的APP右上角就会有一个三个点的按钮,这个按钮就是菜单按钮,点开就是我们写的Add和Remove内容,单机菜单的内容,会弹出Toast消息。

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
      when(item.itemId)
      {
          R.id.add_item -> Toast.makeText(this,"You Clicked Add",Toast.LENGTH_LONG).show()
          R.id.remove_item -> Toast.makeText(this,"You Clicked Remove",Toast.LENGTH_LONG).show()
      }

      return true
  }

这段代码,通过区分item的itemId来分辨是选择了菜单的哪一个选项,ItemId是前面在res资源文件中的menu中定义的菜单资源,然后就通过Toast来达到响应的提示内容。

3.2.6 销毁一个Activity

前面讲述了手动创建Activity,现在要学习怎么销毁一个Activity,调用一个内置的API,finish()就好了。

这里我们把button按键响应的按钮监听器代码改一下,调用一下一个API就好了:

这样再单击button1这个按钮,就会自动销毁Activity。

3.2.0 总结

Android项目讲究的是逻辑和视图分离,代码逻辑主要是在Activity中,视图则是在res资源中,通过在res资源中定义的一些标识符,可以直接在代码逻辑中使用来一一对应确定。

3.3 使用intent在Activity之间穿梭

一个完整的Android项目是会在多个Activity之间交换,这一节就是分析如何切换Activity。

3.3.1 使用显示Intent

新建一个Activity文件,这次勾选上Generate Layout File,自动配置布局文件,但不要勾选:

AS会自动帮我们生成一些必要文件:

只不过自动生成的layout文件有点看不懂:

将其替换为和第一个自己手动建立的Activity源代码类似的框架:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <Button
      android:id="@+id/button2"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Button 2"
      />
</LinearLayout>

该代码还是定义了一个Button按钮,只不过这次改名为Button2了,Activity的代码也自动帮我们生成了,暂时也不用改吧,然后还有创建Activity的最后一步,就是在AndroidManifest文件中注册该Activity(通常AS会自动帮忙注册:

这样一个新的Activity就创建完成了,其实还是挺简单的,按照流程来就好了。

这个新建的Activity并不是一个主Activity所以也没有必要添加intent-filter标签来修饰,那么如何来启动这个Activity呢,就要用到Android里面的一个新的概念:Intent

Intent:是Android中的各种组件之间进行交互的一种重要方式,不仅可以用来指明动作,还可以用来传递数据。Intent一般用来启动Activity,启动Service以及发送广播等场景(这里先专注于启动Activity)。

Intent一般分为两种:显示Intent和隐式Intent。

先分析显示Intent:Intent有多个钩子函数的重载,其中一个是Intent(Context packageContext,Class<?>cls),第一个参数Context要求提供一个启动Activity的上下文,第二个参数class用于指定想要启动的目标Activity,通过这个构造函数就可以构建出Intent,那么如何启动这个intent呢,Activity类中提供了一个startActivity()方法专门用来启动Activity,它接受一个Intent参数,这里将构建好的intent传入到startActivity()函数中,就可以启动目标Activity了。

//修改FirstActivity中的button点击事件来实现:
      var button1: Button = findViewById(R.id.button1)
      button1.setOnClickListener {
          val intent = Intent(this,SecondActivity::class.java)
          startActivity(intent)
      }
//这里首先新建了一个Intent对象,第一个参数传入this,也就是把FirstActivity作为上下文
//第二个参数传入了SecondActivity::class.java作为启动目标的activity
//在Kotlin中的SecondActivity::class.java就和java里面的SecondActivity.class的写法一样
//接下来再通过这个startActivity()来执行这个Intent就好了。

总结:建立一个intent来指定下一个Activity,然后再通过API调用Intent就可以跳转到下一个Activity。

3.3.2 隐式调用Intent

隐式调用比显示调用要麻烦很多,采用一些列的action和category等信息来调用,然后由系统去分析这个Intent,并找出合适的Activity来启动,系统会自动找出可以响应该隐士Intent的Activity来调用,通过在<active>标签下配置<intent-filter>的内容,可以指定当前的Activity能够响应的action和category:

        <activity android:name=".SecondActivity">
          <intent-filter>
              <action android:name="com.example.activitytest.ACTION_START"/>
              <category android:name="android.intent.category.DEFAULT"/>
          </intent-filter>
      </activity>

在这个<action>标签中我们指明了当前Activity中可以响应com.example.activitytest.ACTION_START这个action,而<category>这个标签中则附加了一些附加信息,更精确地指明了当前Activity能够响应的Intent中还可能带有的category,只有action和category中的内容同时匹配Intent中的内容时,这个Activity才能响应该Intent。

修改FirstActivity中按钮的点击事件:

        var button1: Button = findViewById(R.id.button1)
      button1.setOnClickListener {
          val intent = Intent("com.example.activitytest.ACTION_START")
          startActivity(intent)
      }

这里使用了Intent的另一个构造函数,直接将action传了进来,而category有一个默认值:android.intent.category.DEFAULT,所以这里就可以不用传参了。每一个Intent中只能指定一个action,但能指定多个category,当这个Intent触发时,随之绑定的都会触发。

3.3.3 更多的隐式调用Intent用法

使用隐式Intent不仅可以启动自己程序内的Activity,还可以启动其它程序的Activity。

修改FirstActivity中按钮点击事件的代码:

        var button1: Button = findViewById(R.id.button1)
      button1.setOnClickListener {
          val intent = Intent(Intent.ACTION_VIEW)
          intent.data = Uri.parse("https://www.baidu.com")
          startActivity(intent)
      }

这里指定了Intent的action是Intent.ACTION_VIEW这是android系统内置的动作,它的常量值为android.intent.action.VIEW,然后通过Uri.parse()函数,将一个网址解析为uri对象,再调用intent的setData()函数将这个uri对象传递进去。最后的内置API:startActivity函数就是直接调用了这个intent对应的Activity。

这样再单击按钮button1就会直接进入系统内置的浏览器并且访问前面输入的url网站了。

还可以在AndroidManifest文件中的<intent-filter>标签中再配置一个<data>标签,用于更精确地指定当前Activity能够响应的数据。

<data>可以配置一下数据:只有当<data>标签中指定的内容和Intent中携带的Data内容完全一致时,才能响应对应的Intent。

   
android:scheme 用于指定数据的协议部分,就好比前面的url的https这一部分
android:host 用于指定数据的主机名部分:好比前面那个的www.baidu.com
android:port 用于指定数据的端口部分,一般紧随在主机名后面
android:path 用于指定域名后面的部分
android:mimeType 用于指定可以处理的数据类型,允许使用通配符的方式来指定。

比如前面的响应浏览器访问百度,如果把android:scheme指定为https那么就只能响应https协议的Intent了。

例如:这里我们新建一个Activity来响应网页的intent。

1 新建一个Activity叫ThirdActivity,再新建一个layout布局文件叫third_layout :

然后修改third_laytout文件内容为以下代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <Button
      android:id="@+id/button3"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="button3"
      />
</LinearLayout>

ThirdActivity的代码可以不用更改,最后再在AndroidManifest.xml中修改ThirdActivty的注册信息:

代码讲解

这里首先用 action和category指定了intent的调用响应值,然后<data android:scheme中指定了响应的协议必须是https协议。

这样再启用后就会有选择了,是使用普通的chrome还是使用只能有https。

3.3.4 向下一个Activity传递数据

使用Intent启动Activity的时候还可以传递数据。

Intent中提供了一系列的putExtra()函数的重载,可以把想要传递的数据暂存在Intent中,然后在启动另一个Activity后,只需要将其从Intent数据中取出就可以了。

比如说:在FirstActivity中有一个字符串想传递给ThirdActivity中就可以这样写:

button1.setOnClickListener{
val data = "Hello ThirdActivity"
val intent = Intent(this,ThirdActivity::class.java)
intent.putExtra("extra_data",data)
startActivity(intent)
}

这段代码采用的显示传递intent,然后通过putExtra()来传递字符串,putExtra的第一个参数是健用于之后从Intent中取值,第二个参数才是真正要传递的数据。

然后再在ThirdActivity中将传递的数据取出来打印,代码如下:

class ThirdActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.third_layout)
      val extraData = intent.getStringExtra("extra_data")
      Log.d("ThirdActivity","extra data is $extraData")
  }
}

安卓开发(3)—1— Activity的更多相关文章

  1. 安卓开发笔记——深入Activity

    在上一篇文章<安卓开发笔记——重识Activity >中,我们了解了Activity生命周期的执行顺序和一些基本的数据保存操作,但如果只知道这些是对于我们的开发需求来说是远远不够的,今天我 ...

  2. 安卓开发入门之activity

    安卓开发主要用到的是java语言,对于一个activity,自己写的程序可以继承至Activity,该Activity先会运行一个叫 onCreat()的类,可以在其中申明一些初始化的函数等,这个函数 ...

  3. 学习安卓开发[2] - 在Activity中托管Fragment

    目录 在上一篇学习安卓开发[1]-程序结构.Activity生命周期及页面通信中,学习了Activity的一些基础应用,基于这些知识,可以构建一些简单的APP了,但这还远远不够,本节会学习如何使用Ac ...

  4. 安卓开发-intent在Activity之间数据传递

    安卓开发-intent在Activity之间数据传递 [TOC] intent实现普通跳转 使用intent的setclass方法,示例(由此界面跳转到NewActivity界面) //使用setOn ...

  5. 安卓开发-Activity-多个Activity的开发方法。

    原文链接:https://blog.csdn.net/weixin_38420342/article/details/84344496 一.切换Activity的5种方式 Intent intent ...

  6. Xamarin安卓开发:去掉Activity的头部标题栏及全屏显示

    http://blog.csdn.net/u012234115/article/details/35814209 以下是用修改布局文件的方法,其实还有用C#代码的方法. 打开AndroidManife ...

  7. 学习安卓开发[3] - 使用RecyclerView显示列表

    在上一篇学习安卓开发[2] - 在Activity中托管Fragment中了解了使用Fragment的好处和方法,本次记录的是在进行列表展示时RecyclerView的使用. RecyclerView ...

  8. 安卓开发30:AsyncTask的用法

    http://blog.csdn.net/initphp/article/details/10392093 安卓开发笔记系列(43)  在开发Android应用时必须遵守单线程模型的原则: Andro ...

  9. 安卓开发笔记——关于照片墙的实现(完美缓存策略LruCache+DiskLruCache)

    这几天一直研究在安卓开发中图片应该如何处理,在网上翻了好多资料,这里做点小总结,如果朋友们有更好的解决方案,可以留言一起交流下. 内存缓存技术 在我们开发程序中要在界面上加载一张图片是件非常容易的事情 ...

随机推荐

  1. JPEG头部解析

    6.3 JPEG格式       6.3.1简介  微处理机中的存放顺序有正序(big endian)和逆序(little endian)之分.正序存放就是高字节存放在前低字节在后,而逆序存放就是低字 ...

  2. OO第三单元作业(JML)总结

    OO第三单元作业(JML)总结 目录 OO第三单元作业(JML)总结 JML语言知识梳理 使用jml的目的 jml注释结构 jml表达式 方法规格 类型规格 SMT Solver 部署JMLUnitN ...

  3. MySQL中MyISAM为什么比InnoDB查询快

    大家都知道在MySQL中,MyISAM比InnoDB查询快,但很多人都不知道其中的原理. 今天我们就来聊聊其中的原理,另外也验证下是否MyISAM比InnoDB真的查询快. 在探索其中原理之前,我们先 ...

  4. 大数据开发-Flink-1.13新特性

    介绍 大概4月,Flink1.13就发布了,参加 了Flink1.13 的Meetup,收获还是挺多,从大的方面讲就是FlingSql的改进和优化,资源调度管理方面的优化,以及流批一体Flink在运行 ...

  5. Linux中169.254.0.0/24的路由来自哪里

    在Linux中,发现每次系统启动时,都会将(169.254.0.0/16)路由启动并将其添加到路由表中.但是并不知道这条路由具有什么功能和它到底来自于哪里? [root@master01 ~]# ro ...

  6. [bug] Flask:jinja2.exceptions.UndefinedError: 'None' has no attribute 'id'

    问题 Python Flask做的购物网站,添加购物车时,提示错误 解决 检查发现是MySQL中不正常的空数据导致,删除此条记录即可 参考 https://www.jb51.cc/python/186 ...

  7. [Qt] 事件机制(四)

    滚轮事件:滚动滚轮实现窗口大小缩放 widget.h中增加: protected: void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; void ...

  8. downloader middleware的三个methods不同返回的情况

    要激活一个meddleware, 要在设置里面添加.例如: DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.CustomDownloaderMidd ...

  9. Linux(CentOS7)下安装jdk1.8

    Linux(CentOS7) 下安装 jdk1.8 操作过程. 一.检查是否自带jdk rpm -qa|grep java 如果存在则用下面命令删除,xxx yyy zzz代表查询出来的自带jdk名称 ...

  10. 如何彻底禁止 macOS Big Sur 自动更新,去除更新标记和通知

    作者:gc(at)sysin.org,主页:www.sysin.org 请访问原文链接:https://sysin.org/article/Disable-macOS-Update/,查看最新版.原创 ...