Android Studio学习笔记——数据库存储


数据持久化技术就是将内存中瞬时数据保存到存储设备中,保证关机或者重启之后不会数据丢失。

6.1持久化技术简介

Android中主要提供了三种方式用于简单的实现数据持久化功能,即文件存储、SharedPreference存储以及数据库存储。除此之外,还有其他方式,比如说存在SD卡中。文件存储、SharedPreference存储以及数据库存储这三种比存在SD卡中简单,而且更安全。

6.2 文件存储

文件存储不对数据进行任何格式化的处理,适合存储一些简单的文本数据或二进制数据。如果想要存储复杂的数据,就要自定义一套自己的格式规范,这样以后方便从文件中重新解析出来。

将数据存储到文件中

Context类提供了一个openFileOutput()方法,可将数据存到文件中。
这个方法接收两个参数:

  • 第一个参数:文件名。(不可以包含路径,都默认存储到/data/data/<package name/files/)
  • 第二个参数:文件的操作模式。有两种。
    • MODE_PRIVATE:默认操作模式,指定同名文件会覆盖源文件内容。
    • MODE_APPEND:如果文件存在,则往文件末尾追加内容。不存在同名文件则创建新文件。

openFileOutput()返回一个FileOutputStream对象,得到该对象可以使用Java流的方式将数据写入到文件中了。

public void save(){
        String data="Data to save";
        FileOutputStream out=null;
        BufferedWriter writer=null;
        try{
            out=openFileOutput("data", Context.MODE_PRIVATE);
            writer=new BufferedWriter(new OutputStreamWriter(out));
        }
        catch (IOException e){
            e.printStackTrace();
        }
        finally {
            try {
                if(writer!=null){
                    writer.close();
                }
                
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }

从文件中读取数据



public class MainActivity extends AppCompatActivity {
    private EditText edit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        edit=(EditText) findViewById(R.id.edit);

        String inputText=load();
        if(!TextUtils.isEmpty(inputText)){
            edit.setText(inputText);
            edit.setSelection(inputText.length());
            Toast.makeText(this,"Restoring succeeded ",Toast.LENGTH_SHORT).show();
        }
    }

    public void save(String inputText){
        String data="Data to save";
        FileOutputStream out=null;
        BufferedWriter writer=null;
        try{
            out=openFileOutput("data", Context.MODE_PRIVATE);
            writer=new BufferedWriter(new OutputStreamWriter(out));
            writer.write(inputText);
        }
        catch (IOException e){
            e.printStackTrace();
        }
        finally {
            try {
                if(writer!=null){
                    writer.close();
                }

            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    public void onDestroy(){
        super.onDestroy();
        String inputText=edit.getText().toString();
        save(inputText);
    }

    public String load(){
        FileInputStream in=null;
        BufferedReader read=null;
        StringBuilder content=new StringBuilder();
        try{
            in=openFileInput("data");
            read=new BufferedReader(new InputStreamReader(in));
            String line="";
            while((line =read.readLine())!=null){
                content.append(line);
            }

        }catch (IOException e){
            e.printStackTrace();
        }
        finally {
            try {
                if(read!=null){
                    read.close();
                }

            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

6.3 SharedPreferences存储

不同于文件的存储方式。这个是使用键值对的方式来存储数据的。保存一条数据的时候,需要给这条数据提供一个对应的键。这个存储方式支持多种不同的数据类型。如果存储的数据类型是整型,那么读取出来的数据也是整形。如果存储的数据是字符串,那么读取出来的数据也是一个字符串。

6.3.1 将数据存储到是SharedPreferences中

如果要想使用SharedPreferences,所以先要获取到SharedPreferences对象。安卓一共的三种方法用来得到是SharedPreferences对象。

  1. Context类中的getSharedPreferences()方法。
    此方法接收两个参数,第一个参数用于指定这个文件的名称,如果指定的文件不存在,则会创建一个新的,SharedPreferences文件都是存放在/data/data/<package name /<shared_prefs目录下。
    第二个参数用于指定操作模式,目前只有MODE_PRIVATE一种模式可选,它是默认的操作模式。和直接传入0的效果是相同的,只有当前的应用程序才可以对这个SharedPreferences文件进行读写。其他几种操作模式均已被废弃。
  2. Activity类中的getPreferences()方法。
    这个方法和第一个Context类中的getSharedPreferences()方法很相似,不过这个方法只接受一个参数。使用这个方法会自动将当前活动的类名作为SharedPreferences文件名。
  3. PreferenceManager类的getDefaultSharedPreferences()方法
    是一个静态的方法,它接自动使用当前应用程序的包名作为前缀来命名这个SharedPreferences文件。得到了这个SharedPreferences对象之后就开始向这个文件中存储数据了。主要分为以下三个步骤实现:
    第一步,要用这个SharedPreferences对象的edit()方法来获取一个SharedPreferences.Editor对象。
    第二步,向这个SharedPreferences.Editor对象中添加数据,比如添加一个布尔型就用这个putBoolean()方法。添加一个字符串,则使用putString()方法,以此类推。
    第三步,用apply()方法将添加的数据提交,从而完成数据存储。
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
            
            
        });

        Button saveData=(Button) findViewById(R.id.save_data);
        saveData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SharedPreferences.Editor editor=getSharedPreferences("data",MODE_PRIVATE).edit();
                editor.putString("name","Tom");
                editor.putBoolean("married",false);
                editor.putInt("age",28);
                editor.apply();
            }
        });
    }
}

6.3.2 从SharedPreferences中读取数据

每一种get方法都对应了一种put的方法。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;


        });

        Button saveData=(Button) findViewById(R.id.save_data);
        saveData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SharedPreferences.Editor editor=getSharedPreferences("data",MODE_PRIVATE).edit();
                editor.putString("name","Tom");
                editor.putBoolean("married",false);
                editor.putInt("age",28);
                editor.apply();
            }
        });

        Button restoreData=(Button) findViewById(R.id.restore_data);
        restoreData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SharedPreferences pref=getSharedPreferences("data",MODE_PRIVATE);
                String name=pref.getString("name","");
                int age=pref.getInt("age",0);
                boolean married=pref.getBoolean("married",false);
                
            }
        });
    }
}

6.3.3 实现记住密码功能

activity_login.xmll

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">

        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="18sp"
            android:text="Account"/>
        <EditText
            android:id="@+id/account"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">

        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="18sp"
            android:text="Password:"/>
        <EditText
            android:id="@+id/password"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"
            android:inputType="textPassword"/>
    </LinearLayout>

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <CheckBox
            android:id="@+id/remember_pass"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <TextView
            android:textSize="18sp"
            android:text="Remeber password"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    <Button
        android:id="@+id/login"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:text="Login"/>
</LinearLayout>

LoginActivity.java

package com.example.broadcastbestpractice;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

import java.util.prefs.PreferenceChangeEvent;

public class LoginActivity extends BaseActivity{
    private EditText accountEdit;
    private EditText passwordEdit;
    private Button login;

    private SharedPreferences pref;
    private SharedPreferences.Editor editor;
    private CheckBox rememberPass;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        
        pref = PreferenceManager.getDefaultSharedPreferences(this);
        rememberPass=(CheckBox)findViewById(R.id.remember_pass);
        boolean isRemeber=pref.getBoolean("remember_password",false);
        if(isRemeber){
            //将账号和密码都设置到文本框
            String account=pref.getString("account","");
            String password=pref.getString("password","");
            accountEdit.setText(account);
            passwordEdit.setText(password);
            rememberPass.setChecked(true);
        }

        accountEdit=(EditText) findViewById(R.id.account);
        passwordEdit=(EditText) findViewById(R.id.password);
        login=(Button) findViewById(R.id.login);
        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String account=accountEdit.getText().toString();
                String password=passwordEdit.getText().toString();
                if(account.equals("admin")&&password.equals("123")){
                    editor=pref.edit();
                    //如果复选框被选中
                    if(rememberPass.isChecked()){
                        editor.putBoolean("remember_pass",false);
                        editor.putString("account",account);
                        editor.putString("password",password);
                    }else{
                        editor.clear();
                    }
                    editor.apply();

                    Intent intent=new Intent(LoginActivity.this,MainActivity.class);
                    startActivity(intent);
                    finish();
                }else{
                    Toast.makeText(LoginActivity.this,"account or password id invalid",Toast.LENGTH_SHORT).show();
                }

            }
        });
    }
}

6.4 SQLite数据库存储

这是一款轻量级的关系型数据库,它的运算速度非常快,但资源很少,通常只需要几百kb的内存就足够了,因此特别适合在移动设备上使用。SQLite不仅支持标准的SQL语,还遵循数据库的acid事务。

6.4.1 创建数据库

安卓为了让我们能够更加方便的管理数据库,专门提供了一个SQLiteOpenHelper主类。借助这个类就可以非常简单的对数据库进行创建和升级。

  • SQLiteOpenHelper这一个抽象类,如果要使用这个类的话,就需要创建一个自己的帮助类去继承它。

  • SQLiteOpenHelper有两个抽象方法。一个是onCreate(),一个是onupgrade()。需在自己的帮助类里面重写这两个方法。分别在这两个方法中去实现创造和升级数据库的逻辑。

  • SQLiteOpenHelper还有两个非常重要的实例方法。一个是getReadableDatabase(),另一个是getWritableDatabase()。两个方法都可以创建或者打开一个现有的数据库,如果数据库已经存在则打开,否则创建一个新的数据库。并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候,比如磁盘空间已满。getReadableDatabase()方法返回的对象将以只读的方式去带数据。getWritableDatabase()方法则将出现异常。

  • 有两个构造方法可以重写,一般使用参数少一点的那个构造方法即可。是构造函数方法中接收四个参数,第一个参数是context,必须有这个才能对数据库进行操作。第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回一个自定义的Cursor游标,一般都是传入nulll。第四个参数,表示当前数据库的版本号,可用于对数据库进行升级操作。构建出的实例之后再调用它的getReadableDatabase()或者getWritableDatabase()方法就能够创建数据库。数据库的文件存放在/data/data/<package name/databases/目录下,此时重写的onCreate的方法也会执行。所以通常会在这里去处理一些创建表的逻辑。

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        
        dbHelper=new MyDatabaseHelper(this,"BookStroe.db",null,1);
        Button createDatabase=(Button) findViewById(R.id.creat_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();
            }
        });
    }
}
public class MyDatabaseHelper extends SQLiteOpenHelper {
    public final String CREATE_BOOK ="create table book ("
            + "id integer primary key autoincrement, "
            + "author text,"
            + "price real,"
            +"pages integer,"
            +"name text)" ;
    private Context mContext;
    public MyDatabaseHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version){
        super(context,name,factory,version);
        mContext=context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

6.4.2 升级数据库

再加一个数据库表,记录图书的分类。

public class MyDatabaseHelper extends SQLiteOpenHelper {
    public final String CREATE_BOOK ="create table book ("
            +"id integer primary key autoincrement, "
            +"author text,"
            +"price real,"
            +"pages integer,"
            +"name text)" ;
    public final String CREATE_CATEGORY ="create table Category ("
            +"id integer primary key autoincrement, "
            +"category_name text,"
            +"category_code integer)";

    private Context mContext;
    public MyDatabaseHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version){
        super(context,name,factory,version);
        mContext=context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext,"Create 成功",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

看上去挺对的,现在运行一下程序,点击Create database按钮,没有弹出"Create 成功"的提示。
没有创建成功的原因是因为之前的bookstore数据库已经存在了,不管怎样点Create database按钮,这个oncreate方法中都不会再次执行,因此新添加的表就无法得到。
解决方法有两种。一种是卸载程序重新运行。另一种方法是在升级功能函数里面加下面几行代码。

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }

如何让这个onUpgrage的方法能够执行?SQLiteOpenHelper的构造方法接收四个参数,最后一个参数是版本号,版本号默认传入是1,只要传入一个比1大的数就可以让onUpgrade的方法执行。
。。。
dbHelper=new MyDatabaseHelper(this,“BookStroe.db”,null,2);
Button createDatabase=(Button) findViewById(R.id.creat_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
。。。

6.4.3 添加数据

Button addData=(Button) findViewById(R.id.addData);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db=dbHelper.getWritableDatabase();
                ContentValues values=new ContentValues();
                values.put("name","The Da vinci Code");
                values.put("pages",454);
                db.insert("Book",null,values);
                
                values.clear();
                values.put("name","the lost Symbol");
                values.put("pages",349);
                db.insert("Book",null,values);
            }
        });

6.4.4 更新数据

找到书名为The Davinci Code的一组数据,将这本书的价格改为17.52

Button updateData=(Button) findViewById(R.id.updateData);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db=dbHelper.getWritableDatabase();
                ContentValues values=new ContentValues();
                values.put("price",17.52);
                db.update("Book",values,"name=?",new String[]{"The Davinci Code"});
            }
        });

6.4.5 删除数据

删除页数超过500页的书

 Button deleteData=(Button) findViewById(R.id.deleteData);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db=dbHelper.getWritableDatabase();
                ContentValues values=new ContentValues();
                db.delete("Book","pages>?",new String[]{"500"});
            }
        });

6.4.6 查询数据

Button queryData=(Button) findViewById(R.id.queryData);
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db=dbHelper.getWritableDatabase();
                Cursor cursor=db.query("Book",null,null,null,null,null,null);
                if(cursor.moveToFirst()){
                    do{
                        @SuppressLint("Range") String name=cursor.getString(cursor.getColumnIndex("name"));
                        @SuppressLint("Range") int pages=cursor.getInt(cursor.getColumnIndex("pages"));

                    }while(cursor.moveToNext());
                }
                cursor.close();
            }

        });

6.4.7 使用SQL操作数据库

直接使用SQL来完成增删改查。
添加数据
db.execSQL(“insert into Book (name,author,pages,price) values(?,?,?,?)”,new String[]{“The Da Vinci Code”,"Dan ",“454”,“16.35”} );

查询数据
db.rawQuery(“select * from Book”,null);

6.5 使用LitePal操作数据库

6.5.1 LitePal简介

是一个开源的Android数据库框架。采用了对象关系映射(ORM)的模式,并将我们平时开发最常用的一些数据库功能进行了封装。不用编写SQL就完成增删改查。

6.5.2 配置LitePal

怎样才能在项目中使用开源库?过去的方式比较复杂,下载开源库的jar包或者源码,然后再集成到项目中。现在简单多了,大多数的开源项目都会将版本提交到jcenter上,需要在app/build.gradle文件中声明该开源库的引用就可以了。

后续更新…

6.5.3 创建和升级数据库

6.5.4 增加

6.5.5 更新

6.5.6 删除

6.5.6 查询

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android Studio是Google推出的Android应用程序开发工具,它集成了开发、调试、打包等功能。要学习使用Android Studio,需要了解以下几个方面的知识: 1. Java基础: Android开发是基于Java语言的,所以要学习Android Studio首先要掌握Java基础知识。 2. Android基础: 了解Android操作系统的基本构架和常用组件,如Activity、Service、BroadcastReceiver等。 3. Android Studio使用: 了解Android Studio的基本界面和常用功能,如创建工程、编写代码、调试程序等。 4. Android SDK: 了解Android SDK的安装和配置,以及如何使用SDK Manager来下载SDK并配置项目。 5. 练习实践: 多练习实际项目,熟悉Android Studio的使用,并不断练习和完善自己的技能。 ### 回答2: Android Studio 是一个为 Android 来开发的整体开发环境。它基于 IntelliJ IDEA ,强调速度和智能操作,并致力于为应用程序开发提供高效率的开发工具。Android Studio 的推出,使得 Android 开发者更加容易地创建高质量的应用程序。 首先,要学 Android Studio ,你需要首先了解一些基本知识。学习 Android Studio 的工具包括 Gradle 、 Kotlin 和 Java 等。通过学习这些基础知识,你可以了解不同的语言、工具和框架。 在学习 Android Studio 时要使用实战性的方法。也就是说,每次学习新的东西时,你需要找到一个相关的例子。这样可以帮助你更好地理解它。如果你使用 Android Studio 模板,这将非常有用。这些模板可以帮助你创建常见的应用程序结构,并且你可以基于这些模板创建自己的应用程序。 另外,还有很多不同的工具和插件可以帮助你学习 Android Studio 。例如, Android Studio 网站上有很多有用的文章和教程,可以帮助你更好地理解 Android Studio 。还有很多在线工具可以帮助你实现特定的功能,在初学者阶段,这些工具可以为学习的难度减轻很多。 总之,学习 Android Studio 任重而道远。需要有耐心和时间,还需要不断地尝试和实践。在这个过程中,你可以尝试教学资料、交流学习合作、进一步增强你的知识水平。通过不断的应用和实践,一定可以成为一名优秀的 Android 开发者并圆满地完成应用开发。 ### 回答3: 作为一个应用开发者,学习使用安卓应用程序开发套件非常重要。Android Studio是Google出品的最新安卓开发工具,它具有多种强大的工具和功能,可以极大地提高应用程序的开发效率和质量。在学习过程中,个人对Android Studio的理解主要体现在以下几个方面。 首先,要开始使用Android Studio,需要了解它的基本结构和工具。Android Studio主要由三个主要组件组成:IDE、SDK、和Emulator。IDE是开发者使用的主要工具。它提供了编写、测试和调试代码所需的所有基本功能,包括视觉化设计器,代码编辑器和调试工具。SDK是开发应用程序所需的软件开发包。它包括实用程序和库,可用于在应用程序中实现预定功能。Emulator是一个虚拟的安卓设备,可以用来在开发应用程序时模拟真实设备上的应用程序运行情况。 其次,一些基本的编程知识也必不可少,例如Java编程、XML语言、UI界面设计等。Java是Android Studio中最常用的编程语言,用于编写应用程序的逻辑代码;XML语言则用于设计UI界面。在学习这些基本知识时,建议首先了解Java语言特性和面向对象编程理念,熟悉它们的基本语法和数据类型。同时,也可以通过在线教程和网课等方式加强对UI设计和布局的理解。 最后,学会使用网上的资源和社区的帮助非常重要。Android Studio的开发者社区很大,有很多在线资源可以帮助开发者的开发学习,例如stack overflow、CSDN社区等。同时,Google官方的开发者网站也提供了大量的文档资料、教程、API使用说明等。 总之,Android Studio学习需要进行持续不断的针对不同方面的学习和实践。要充分运用Android Studio的强大功能,建议在掌握基础知识的基础上,多做实际的项目练习,不断提高自己的技术水平和代码能力,才能成为一名优秀的安卓应用程序开发者。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值