`

Getting Started-----Saving Data

 
阅读更多

        绝大多数的Android App都需要保存数据,即使仅仅在onPause()方法里保存app状态信息以免user进度信息被丢失。大多数非著名的app也可能要保存用户设置信息。一些应用需要在文件和数据库保存大量的信息。本文将向你讲述Android主要的数据存储方式。包括:

  • 在SharedPreferences文件里保存简单数据类型的key-value键值对。
  •  在Android文件系统里保存任意类型的文件。
  • 使用SQLite数据库

        Lessons

          Saving Key-Value Sets

              Learn to use a shared preferences file for storing small amounts of information in key-value pairs.

          Saving Files 

               Learn to save a basic file, such as to store long sequences of data that are generally read in                        order

           Saving Data in SQL Databases 

              Learn to use a SQLite database to read and write structured data.

 

 

              

    Saving Key-Value Sets

          如果你有少量的key-value数据需要保存,你应该使用SharePreferences APIs。一个SharedPreferences对象指向一个包含key-value对的文件,并提供了简单的方法读写它们。SDK框架管理每个SharedPreferences文件,你可以指定该文件是私有的还是共享的。

         本文告诉你如何使用SharedPreferences的APIs存储和检索简单的值。

        注: SharedPreferences  APIs仅仅用于读和写键-值对,你不应该使用Preference APIs混淆它们。Preference是一个帮助你处理你的app设置的用户界面(虽然SharePrerences是保存用户设置的preference界面的一个默认实现类)。更多如何使用Preference APIs的信息,参见Settings 向导。

 

       Get a Handle to a SharedPreferences

       你能调用如下两个方法之一产生一个新的shared preferences文件或者访问一个已存在的sharedPreferences文件。

  •   getSharedPreferences()  — 如果需要多个用名字标识的sharedpreferences文件使用该方法,你能用第一个参数指定文件名字。你必须从你的app里的任何Context上调用该方法。
  •   getPreferences()  — 该方法在Activity上调用,如果在该Activity里你只需要一个sharedPreferences文件可以调用该方法。因为该方法检索一个默认的sharedPreferences。该默认文件属于调用该方法的activity,你不需要提供一个名字。

        例如,下面的代码在一个fragment里执行。它访问一个由R.string.preference_file_key字符串资源指定的sharedPreferences文件。该文件已私有模式访问,因此,仅仅你的app能访问该文件。

       

Context context = getActivity();
SharedPreferences sharedPref = context.getSharedPreferences(
        getString(R.string.preference_file_key), Context.MODE_PRIVATE);

         

        当命名你的sharedPreferences文件时,你应该使用一个你的app范围内唯一标识的名字。例如“com.example.myapp.PREFERENCE_FILE_KEY”。

        或者,你仅仅在某个activity里只需要一个shared preferences文件,你能使用getPreferences()方法:

       

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);

         注意:如果你用MODE_WORLD_READABLE或者MODE_WORLD_WRITEABLE模式产生一个shared preferences文件,那么任何知道该文件名的app都能访问你的数据。

        

        Write to Shared Preferences

        为了写数据到shared preferences文件,调用SharedPreferences的edit()方法产生一个SharedPreferences.Editor对象。

        调用例如putInt()或者putString()方法传递要写入的key-value值,然后调用commit()方法保存这些值。例如:

       

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(getString(R.string.saved_high_score), newHighScore);
editor.commit();

         

        Read from Shared Preferences

        为了从shared preferences文件读取数据,调用getInt()或者getString()等方法,提供你要的数据的key值,如果key不存在,将返回一个默认值。例如:

       

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
int defaultValue = getResources().getInteger(R.string.saved_high_score_default);
long highScore = sharedPref.getInt(getString(R.string.saved_high_score), defaultValue);

 

   

        

   Saving Files

        Android使用的文件系统类似于其他平台的基于磁盘的文件系统。本文描述如何使用Android的文件系统和 File APIs读和写文件。

        File对象适合从头到尾没有调过的读和写大量的数据。例如,图片文件和网络交互的数据。

        本文讲述在你的app里如何执行基本的文件相关的操作。本文假设你对Linux文件系统基础和java.io包里的标准文件输入/输出APIs很熟悉。

        

        Choose Internal or External Storage

        所有的Android设备有两个文件存储区域:“internal”和“external”存储。这些名字来自于Android早期,当时大多数设备提供内置的非易失的内存(内部存储),同时提供一个可移除存储媒介例如一个micro SD卡(外部存储)。一些设备把永久存储空间划分为“internal” 和 “external”部分,因此,甚至没有一个可移除的存储媒介,也总是存在“internal” 和 “external”两个存储空间,且外部存储不管是不是可移除的,API行为都是相同的。

        

         提示:虽然app默认的安装到内置存储,但你能在manifest文件里指定android:installLocation 属性让你的app安装到外部存储。当APK大小是非常大,同时用户有外置存储,并且外置存储比内置存储空间更大时,需要可能会需要改选项。

        

        Obtain Permissions for External Storge

        为了写到外部存储,你必须在manifest file里添加WRITE_EXTERNAL_STORAGE权限:

        

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

         注意:当前,app不用指定专门的权限而去读外部存储。然而,以后发版的android版本将改变这点。如果你的app需要读(但不写)外部存储,那么你将需要声明READ_EXTERNAL_STORAGE权限。为了确保你的应用能正常的运行,你应该总是声明该权限,即使该改变还没有生效。

       

<manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    ...
</manifest>

        然而,如果你的app使用WRITE_EXTERNAL_STORAGE权限,那么,它隐式的包含有读外部存储的权限。

     

        在内部存储上保存文件你不需要任何权限。你的app始终有读和写内部存储文件的权限。

  

        Save a File on Internal Storage

        当保存文件到内部存储时,你能调用下面两个方法里的一个获取合适的文件目录。

 

       getFilesDir()

        返回一个代表你的应用app的内部目录的文件。

 

getCacheDir()

 

        返回一个内部存储目录的文件作为你的app的临时缓存文件。一定要一旦该缓存文件不再需要时删除该文件,从而实现合理的内存大小限制,例如1M。如果系统开始变的存储紧张,系统将不给你任何警告的情况下删除你的缓存文件

        

        为了在这些目录中产生新的文件,你能使用File()构造器,传递上面两个方法中的一个作为你的内部存储目录,例如:

        

File file = new File(context.getFilesDir(), filename);
          你能调用openFileOutput()方法得到一个FileOutputStream流,然后向你的内部存储文件里写数据。例如,下面是如何写一些文本到一个文件。

 

         

String filename = "myfile"; 
String string = "Hello world!"; 
FileOutputStream outputStream;  
try {   
            outputStream = openFileOutput(filename, 
            Context.MODE_PRIVATE);  
           outputStream.write(string.getBytes());  
            outputStream.close(); 
      } catch (Exception e) {   
            e.printStackTrace(); }

         或者,如果你需要缓存一些文件,你应该使用createTempFile()方法。例如,下面的方法从一个URL里抽取文件名,然后用你的app内存缓存目录名产生一个文件。

        

public File getTempFile(Context context, String url) {     
        File file;     
        try {         
              String fileName = Uri.parse(url).getLastPathSegment();         
              file = File.createTempFile(fileName, null, context.getCacheDir());    
          catch (IOException e) {         
               // Error while creating file     
             }    
              return file; 
        }

         注:你的app的内部存储目录在android文件系统的一个特定的位置通过app的包名被指定。理论上,如果你设置你的内部文件为可读模式,其他的app能读取你的内部文件。当然,其他的app也将需要知道你的app的包名和文件名。其他的应该不能浏览你的内部存储目录,也没有读写访问权限,除非你显示的设置文件为可读和可写模式。因此一旦你设置你的内存存储中的文件为MODE_PRIVATE模式,其他的app将不能访问。

 

        因为外部存储可能不是总是有效的——例如当用户挂载存储到PC或者移除作为外部存储的SD卡时——你应该在访问外部存储之前总是检查该卷是否有效。你能调用getExternalStorageState()方法插叙外部存储状态。如果返回的状态值等于MEDIA_MOUNTED,那么你能读写外部存储文件。例如,下面的方法被用于检查存储是否有效:
        

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}
 

 

          虽然外部存储能被用户或者其他的app修改,有两类文件你能保存在外部存储上:
          Public files

                文件时完全的公开的, 对其他的app和用户是完全可见的。当用户卸载你的app,这些文件应该仍                 然保留,对用户有效。

                例如:用户拍的照片或者下载的文件。

          Private files  

                指仅仅属于你的app,当用户卸载你的app时应该被删除的文件。虽然理论上这些文件也可以被用                   户或者其他的app访问,因为它们在外部存储。当用户卸载你的app时,系统应该删除所有的外部                   存储里私有目录下的所有文件。

                  例如,你的app下载的额外资源或者临时媒体文件。

 

         如果你想在外部存储保存public的文件,使用getExternalStoragePublicDirectory()方法获取SD卡上合适的public目录。该方法接受一个指定文件类型的参数,以便于该文件和其他的公共的文件能逻辑地组织,例如DIRECTORY_MUSIC或者DIRECTORY_PICTURES。如下:

        

public File getAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory. 
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

         如果你想要保存文件是私有的,你能通过调用getExternalFilesDir()方法取得合适的私有目录,传递一个表明目录类型的名字。这种方式产生的目录被添加到一个包含了你的app所有私有文件的父目录。这些,当用户卸载你的app时系统会删除所有的私有文件。

        例如,如下是一个产生个人相片册目录的方法:

        

public File getAlbumStorageDir(Context context, String albumName) {
    // Get the directory for the app's private pictures directory. 
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

         如果系统预先定义的子目录没有一个适合你的文件,你能调用getExternalFilesDir()方法,然后给该方法传递null值。这样系统返回你的app私有文件目录的根目录。

 

        记住通过getExternalFileDir()产生的目录,当用户卸载你的app时,该目录下的文件和该目录会被删除。

如果你想保存的文件在app卸载后仍然有效——例如你的app是一个照相机应用,用户想要保存照片——你应该使用getExternalStoragePublicDirectory().方法。

        不管你是使用getExternalStoragePublicDirectory()方法产生共享文件还是使用getExternalFilesDir()产生私有文件,使用系统提供的API常量例如DIRECTORY_PICTURES作为目录是非常重要的。这些目录名确保文件被系统合理的处理和对待。例如,保存在 DIRECTORY_RINGTONES 里的文件能被系统media scanner分类作为铃声而非音乐。

 

      Query Free Space

      如果你提前知道你要保存多少数据,你可能需要知道是否有足够的空间是有效的,而不引起IOException.这可以通过调用getFreeSpace()或者getTotaolSpace()方法实现。该方法分别提供了存储卷当前的剩余空间和总空间大小。其他的情况下可需要知道SD卡的存储大小信息,例如空间信息在避免超出一定的存储阀值避免写入也是有用的。

        然而,系统并不能保存写入和getFreeSpace()返回值大小一样的字节值。如果剩余空间比你要保存的数据大小多几MB。或者文件系统剩余空间大于10%,那么保存文件操作是安全的。否则,你可能不适合想存储卷里写。

       注:当你不知道你保存的文件大小时,你不应该检查有效空间量,而是试着写文件,然后捕获IOException。例如你将文件从PNG图片格式转换到JPEG格式时,你并不知道转换后的文件大小。

  

        Delete a File

        你应该总是记得删除你不再需要的文件。删除文件最直接的方式就是有一个打开文件的应用,调用其上的delete()方法

        

myFile.delete();

         如果该文件保存在内部存储,你也能获取Contex,调用该对象的deleteFile()方法删除文件:

     

myContext.deleteFile(fileName);

         

       注:当用户卸载你的app时,Android系统会删除:

  •  你保存在内存存储的所有文件
  • 你通过调用getExternalFilesDir()方法保存在外部存储的文件

        然而,你也应该手动的删除调用getCacheDir() 方法产生的缓存文件,也应该删除其他的你不需要的文件。

         

 

       

      Saving Data in SQL Databases

       对于重复的或者结构化的数据保存数据到数据库是一个理想的方式,例如联系人信息。 本文假设你对SQL 数据库的一般知识是熟悉的,帮助你如何在Adnroid上使用SQLite数据库。Android上操作数据库的API在android.database.sqlite包下。

 

        Defina a Schema and Contract

        SQL数据库的主要原则之一是schema:数据库怎么被组织的格式化声明。schema反射到你创建数据库的SQL语句上。schema在产生companion类时是很有用的,例如contract类,其通过系统的和自描述方式显示的指定了你的schema的布局。

        contract类是一个定义URI,表和栏的常量的容器。contract类允许你在相同包里的不同类之间使用同样的常量。这使得你修改的你栏名只需要修改一个地方即可。

        组织contract类的一种好的方式是把数据库的全局的定义放在该类的根上,然后对每个表产生一个内部类来枚举该表的栏。

        注:通过实现BaseColumns接口,你的内部类能继承一个名为_ID的主键属性。Android里一些类例如cursor adaptor期望有该属性。这是不必须的,但是这能使得你的数据库在Android框架上工作和谐。

        例如,下面代码片段定义了表名和某个表的栏名:

        

public final class FeedReaderContract {
    // To prevent someone from accidentally instantiating the contract class,
    // give it an empty constructor.
    public FeedReaderContract() {}

    /* Inner class that defines the table contents */
    public static abstract class FeedEntry implements BaseColumns {
        public static final String TABLE_NAME = "entry";
        public static final String COLUMN_NAME_ENTRY_ID = "entryid";
        public static final String COLUMN_NAME_TITLE = "title";
        public static final String COLUMN_NAME_SUBTITLE = "subtitle";
        ...
    }
}
 

 

        Create a Database Using a SQL Helper 

        一旦你已定义了你的数据库结构,你应该实现产生和维护数据库以及表的方法。下面是一些典型的产生和删除表的语句:

        

private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES =
    "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +
    FeedEntry._ID + " INTEGER PRIMARY KEY," +
    FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
    FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
    ... // Any other options for the CREATE command
    " )";

private static final String SQL_DELETE_ENTRIES =
    "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
 

 

        像保存在内部存储的文件,Android保存你的数据库在与你的app相关联的私有存储空间。这样你的数据是安全的,默认地,这块区域不能被其他的应用访问。

       一些操作数据库的有效API在类SQLiteOpenHelper里 。当你使用该类获取你的数据库引用时,系统可能执行一个耗时操作产生和更新数据库。仅仅在需要时执行而不是应用启动时,所有你需要做的是调用 getWritableDatabase() 或者getReadableDatabase().

        注:因为 getWritableDatabase() orgetReadableDatabase().是耗时操作,确保在后台线程调用它们,例如AsyncTask or IntentService

        为了使用SQLiteOpenHelper,产生该类的子类,重写 onCreate()onUpgrade() and onOpen()回调方法。你可能也想要实现onDowngrade(),但是这不是必须的,视需要而定。

 

        例如,下面是SQLiteOpenHelper类的一个实现,其用到了上面介绍的一些命令:

        

public class FeedReaderDbHelper extends SQLiteOpenHelper {
    // If you change the database schema, you must increment the database version.
    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "FeedReader.db";

    public FeedReaderDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(SQL_CREATE_ENTRIES);
    }
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // This database is only a cache for online data, so its upgrade policy is
        // to simply to discard the data and start over
        db.execSQL(SQL_DELETE_ENTRIES);
        onCreate(db);
    }
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        onUpgrade(db, oldVersion, newVersion);
    }
}
         为了访问你的数据库,实例化你的SQLiteOpenHelper:类的子类:

 

        

FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
         

 

        Put Information into a Database

        通过传递ContentValues对象到insert()方法插入数据到数据库:

        

// Gets the data repository in write mode
SQLiteDatabase db = mDbHelper.getWritableDatabase();

// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_CONTENT, content);

// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
         FeedEntry.TABLE_NAME,
         FeedEntry.COLUMN_NAME_NULLABLE,
         values);
         insert()方法的第一个参数是表名。第二参数用于指定可以插入NULL值的栏名,以防ContentValues为空(如果你设置该参数为“null”,没有值将不能被插入)。

 

 

        Read Inforamtion from a Database

        为了从数据库里读取数据,使用query()方法,传递给该方法你的选择标准和期望的栏。该方法包含insert()和update()的元素,不包含定义你想要去的数据的栏名的行。查询结果以Cursor 对象返回。

        

SQLiteDatabase db = mDbHelper.getReadableDatabase();

// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
    FeedEntry._ID,
    FeedEntry.COLUMN_NAME_TITLE,
    FeedEntry.COLUMN_NAME_UPDATED,
    ...
    };

// How you want the results sorted in the resulting Cursor
String sortOrder =
    FeedEntry.COLUMN_NAME_UPDATED + " DESC";

Cursor c = db.query(
    FeedEntry.TABLE_NAME,  // The table to query
    projection,                               // The columns to return
    selection,                                // The columns for the WHERE clause
    selectionArgs,                            // The values for the WHERE clause
    null,                                     // don't group the rows
    null,                                     // don't filter by row groups
    sortOrder                                 // The sort order
    );
         为了获取Cursor里的一行,使用cursor的移动方法,在你从cursor读取数据时,你必须总是调用该方法。一般地,开始你应该调用moveToFirst()方法,该方法移动游标到结果的开始处。对于每一行,你可以调用Cursor的get方法获取某一个栏的值,例如  getString() or getLong(),对于get方法,你必须传递栏的索引位置给get方法,你能调用getColumnIndex() or getColumnIndexOrThrow()方法获取栏索引,例如:
        
cursor.moveToFirst();
long itemId = cursor.getLong(
    cursor.getColumnIndexOrThrow(FeedEntry._ID)
);
         
        Delete Information from a Database
         为了删除表里的某行,你需要提供表示行的选择标准。数据库API提供了产生选择标准的机制,该机制防止SQL注入。该机制将选择条件分成了选择条款和选择参数。条款定义了查看的栏。参数是绑定到选择从句的值。因为结果不是被规则的SQL语句处理,最小的减少了SQL注入。
        
// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
String[] selectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);
 
       Update a Database
        当你需要修正你的数据库的部分字段的值时,使用update() 方法。
        Updating the table combines the content values syntax of insert() with the where syntax of delete().
SQLiteDatabase db = mDbHelper.getReadableDatabase();

// New value for one column
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);

// Which row to update, based on the ID
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) };

int count = db.update(
    FeedReaderDbHelper.FeedEntry.TABLE_NAME,
    values,
    selection,
    selectionArgs);
 

 

        

  • 大小: 21.2 KB
分享到:
评论

相关推荐

    Tableau.Creating.Interactive.Data.Visualizations

    Data scientists who have just started using Tableau and want to build on the skills using practical examples. Familiarity with previous versions of Tableau will be helpful, but not necessary. What ...

    quick python book 第三版

    Getting started The Quick Python overview PART 2 - THE ESSENTIALS The absolute basics Lists, tuples, and sets Strings Dictionaries Control flow Functions Modules and scoping rules Python programs ...

    Getting.Started.with.React.Native.1785885189

    This book provides a simple and easy way ...Chapter 5: Displaying and Saving Data Chapter 6: Working with Geolocation and Maps Chapter 7: Integrating Native Modules Chapter 8 : Releasing the Application

    Scipy - Scipy Lecture Notes

    Getting Started with Python for Science ##### 1. Python Scientific Computing Ecosystem **1.1 Why Python?** Python has become the lingua franca for scientific computing due to its simplicity, ...

    How.to.Use.IBM.SPSS.Statistics.epub

    Chapter 1 Getting Started Chapter 2 Entering and Modifying Data Chapter 3 Descriptive Statistics Chapter 4 Graphing Data Chapter 5 Prediction and Association Chapter 6 Parametric Inferential ...

    Prentice.Hall.C++.GUI.Programming.with.Qt.4.2nd.Edition.2008.chm

    Getting Started Hello Qt Making Connections Laying Out Widgets Using the Reference Documentation Chapter 2. Creating Dialogs Subclassing QDialog Signals and Slots in Depth Rapid Dialog...

    Packt.Python.for.Finance.2nd.Edition.2017

    Understanding this process is critical for setting up your development environment and getting started with programming. - **Variable Assignment, Empty Space, and Writing Own Programs**: Here, ...

    STATA命令分类列表

    - **Getting Started**:这部分内容主要针对初学者,提供了如何开始使用STATA的基础指南。包括在不同操作系统(如Macintosh、Unix、Windows)下的操作指南。 - **[GS]**:此章节为快速入门手册,适用于Macintosh...

    virtuoso spectre RF tools lecture manual

    Lab 2-1 Getting Started ..... 2-1 Logging In...... 2-1 Starting Cadence Software................. 2-1 Lab 2-2 Running a Voltage Conversion Gain Simulation ...... 2-3 Opening the ne600 Schematic ....

    Matlab面向对象编程

    #### 一、入门指南 (Getting Started) - **面向对象编程概念**:在Matlab中,面向对象编程(OOP)是一种编程范式,它使用类来定义对象的行为和属性。 - **类的基础知识**:了解如何创建类、实例化对象以及调用方法。 ...

    Packt.Python.Journey.from.Novice.to.Expert.2016

    Chapter 1: Getting Started – One Environment per Project Chapter 2: Pythonic Syntax, Common Pitfalls, and Style Guide Chapter 3: Containers and Collections – Storing Data the Right Way Chapter 4: ...

    Learning redis - Stack Overflow contributors

    Chapter 1: Getting started with redis 2 Remarks 2 Versions 2 Examples 2 Overview 2 Redis command line interface 3 Redis "Hello World" 4 Install Redis by using Docker 5 Redis installtion on Windows, ...

    Professional Android 4 Application Development 源代码

    Chapter 2: Getting Started Developing for Android Developing for Mobile and Embedded Devices Android Development Tools Chapter 3: Creating Applications and Activities What Makes an Android Application...

    JProfiler Helper

    ##### Getting Started (B.1) **Quickstart Dialog (B.1.1)** The quickstart dialog simplifies the initial setup process by guiding users through common tasks. Key features include: - Selecting ...

    iOS 10 Programming for Beginners

    Getting Started with the Grid Getting Started with the List Working More with Lists Where Are We? Where's My Data? Foodie Reviews Saving Reviews Universal iMessages Notifications Just a Peek Beta and ...

    Using Perl For Web Programming.pdf

    Limiting Data-File Size H Using the Location Header H Using CGI in Server-Side Includes H G From Here G Chapter 3 Advanced Form Processing and Data Storage Using the POST Method Comparing GET and...

    HTML5 GAMES Creating Fun with HTML5 CSS3 and WebGL 英文PDF

    #### Part 1: Getting Started with HTML5 Games ##### Chapter 1: Gaming on the Web In this chapter, the history of HTML5 is traced, highlighting its evolution and how it has become a viable platform ...

Global site tag (gtag.js) - Google Analytics