• Android异步和线程


    代码仓库:https://github.com/MADMAX110/Starbuzz

    Android应用打开数据库时首先要搜索数据库文件,如果没有找到数据库文件就要创建一个空的数据库。然后它要运行所有SQL命令,在数据库中创建数据库表和需要的所有初始数据。最后还要执行一些查询从数据库得到数据。

    线程合作让生活更美好

    访问一个很慢的数据库会让你的应用看起来好像没有响应。
    线程主要有三种:
    1、主事件线程
    2、呈现线程
    3、你创建的所有其他线程
    如果你不细心,应用几乎所有的工作都可能在主事件线程中完成,因为这个线程运行你的事件方法,如果把数据库代码放在onCreate方法中,主事件线程就会忙于与数据库交互,而不会迅速应对来自屏幕或其他应用的事件。
    如果你的数据库代码要花很长时间,用户就会觉得自己被忽略,或者担心应用是否崩溃了。
    所以这里的技巧时将数据库代码从主事件线程移出来,在后台的一个定制线程中运行。

    AsyncTask完成异步任务

    AsyncTask类允许你在后台完成操作。这些操作运行结束时,就可以在主事件线程中更新视图。
    如果任务是重复的,甚至可以利用这个类发布任务运行的进度。
    要创建AsyncTask,需要扩展AsyncTask类,并实现它的doInBackground方法。这个方法中的代码会在后台线程中运行,所以把数据库代码放在这里非常合适。AsyncTask类还有一个onPreExecute方法,这个方法在doInBackground之后运行。如果需要发布任务进度还可以使用一个onProgressUpdate方法。

    private class MyAsyncTask extends AsyncTask{
    
    //可选,在后台运行的代码之前运行
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
            }
    
    //必须实现这个方法
            @Override
            protected Object doInBackground(Object[] objects) {
                return null;
            }
    
    //允许你发布在后台运行的代码的进度
            @Override
            protected void onProgressUpdate(Object[] values) {
                super.onProgressUpdate(values);
            }
    
    //在后台中的代码结束运行
            @Override
            protected void onPostExecute(Object o) {
                super.onPostExecute(o);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    onPreExecute方法

    这个方法会在后台任务开始之前调用,用来建立任务。
    onPreExecute方法在主事件线程调用,所以它可以访问用户界面中的视图。
    在这里使用onPreExecute方法得到favorite复选框的值,把它放在drinkValues ContentValues对象中。
    这是因为我们需要访问这个复选框视图才能得到它的值,而且这个工作必须在运行数据库代码之前完成。
    我们要在这个方法之外使用另一个属性表示drinkValues ContentValues对象,使得这个类的其他方法也能访问这个ContentValues对象。

        private class UpdateDrinkTask extends AsyncTask<Integer, Void, Boolean>{
            private ContentValues drinkValues;
            
            protected void onPreExecute(){
                CheckBox favorite = (CheckBox) findViewById(R.id.favorite);
                drinkValues = new ContentValues();
                drinkValues.put("FAVORITE", favorite.isChecked());
            }
            
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    doInBackground方法

            @Override
            protected Boolean doInBackground(Integer[] drinks) {
                int drinkId = drinks[0];
                SQLiteOpenHelper starbuzzDatabaseHelper = new StarbuzzDatabaseHelper(DrinkActivity.this);
                try {
                    SQLiteDatabase db = starbuzzDatabaseHelper.getWritableDatabase();
                    db.update("DRINK",
                            drinkValues,
                            "_id = ?",
                            new String[] {Integer.toString(drinkId)});
                    db.close();
                    return true;
                }catch (SQLiteException e){
                    return false;
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    onProgressUpdate方法

    该方法在主事件线程调用,所以可以访问用户界面中的视图。可以使用这个方法更新屏幕上的视图向用户显示进度。要定义这个方法接受什么类型的参数。
    如果由doInBackground方法调用publishProgress,就会运行onProgressUpdate方法,如下所示

            protected Boolean doInBackground(Integer[] count) {
                for (int i = 0; i < count; ++i){
                    publishProgress(i);
                }
            }
    
            @Override
            protected void onProgressUpdate(Integer... progress) {
                super.onProgressUpdate(progress[0]);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    onPostExecute方法

    后台任务完成后调用onPostExecute()方法。它在主事件线程中调用,所以可以访问用户界面中的视图。可以使用这个方法为用户呈现任务的结果。要把doInBackground方法的结果传入onPostExecute方法,所以它的参数必须与doInBackground的返回类型一致

    我们要使用onPostExecute方法检查doInBackground方法中的数据库代码是否成功运行。如果没有,就要向用户显示一个消息。这个工作在onPostExecute方法中完成,因为这个方法可以更新用户界面。doInBackground方法在后台线程中运行,所以不能更新视图。

        protected void onPostExecute(Boolean success) {
            if (!success) {
                Toast toast = Toast.makeText(DrinkActivity.this, "Darabase unavailable", Toast.LENGTH_SHORT);
                toast.show();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    AsyncTask类

    AsyncTask是一个抽象类,它定义了三个泛型参数:Params、Progress和Result。这三个参数在创建AsyncTask的子类并实现其方法时使用,以便更好地处理异步任务。
    Params:这个参数类型是在任务开始执行时传递给AsyncTask的。具体传递的内容根据任务的需要而定,例如,可能是要加载的图片的URL,或者是需要从网络上获取数据的特定字段名称等。
    Progress:这个参数类型用于异步任务执行过程中的进度更新。当任务执行过程中需要更新进度时,可以在任务线程中调用publishProgress()方法,传递当前的进度值,然后在主线程中通过重写onProgressUpdate(Progress…)方法来接收并处理这些进度值。
    Result:这个参数类型是在异步任务执行完成后返回的结果。当任务执行完毕后,可以在任务线程中调用onPostExecute(Result result)方法,传递计算得到的结果,然后在主线程中通过重写此方法来接收并处理这些结果。
    这三个参数在AsyncTask中是非常重要的,它们使得异步任务的执行过程变得更加清晰、有条理。

    完整的DrinkActivity

    package com.hfad.starbuzz;
    
    import androidx.appcompat.app.AppCompatActivity;
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.database.SQLException;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteException;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.CheckBox;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;
    
    public class DrinkActivity extends AppCompatActivity {
    
        public static final String EXTRA_DRINKID = "drinkId";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_drink);
    
            int drinkId = (Integer)getIntent().getExtras().get(EXTRA_DRINKID);
    
            SQLiteOpenHelper starbuzzDatabaseHelper = new StarbuzzDatabaseHelper(this);
            try {
                SQLiteDatabase db = starbuzzDatabaseHelper.getReadableDatabase();
                Cursor cursor = db.query("DRINK",
                        new String[]{"NAME", "DESCRIPTION", "IMAGE_RESOURCE_ID", "FAVORITE"},
                        "_id = ?",
                        new String[] {Integer.toString(drinkId)},
                        null, null, null);
                if (cursor.moveToFirst()) {
                    String nameText = cursor.getString(0);
                    String descriptionText = cursor.getString(1);
                    int photoId = cursor.getInt(2);
                    boolean isFavorite = (cursor.getInt(3) == 1);
    
                    TextView name = (TextView) findViewById(R.id.name);
                    name.setText(nameText);
    
                    TextView description = (TextView) findViewById(R.id.description);
                    description.setText(descriptionText);
    
                    ImageView photo = (ImageView) findViewById(R.id.photo);
                    photo.setImageResource(photoId);
                    photo.setContentDescription(nameText);
    
                    CheckBox favorite = (CheckBox) findViewById(R.id.favorite);
                    favorite.setChecked(isFavorite);
                }
                cursor.close();
                db.close();
            }catch (SQLException e){
                Toast toast = Toast.makeText(this,
                        "Database unavailable",
                        Toast.LENGTH_SHORT);
                toast.show();
            }
        }
    
        public void onFavoriteClicked(View view){
            int drinkId = (Integer)getIntent().getExtras().get(EXTRA_DRINKID);
    
            CheckBox favorite = (CheckBox) findViewById(R.id.favorite);
            ContentValues drinkValues = new ContentValues();
            drinkValues.put("FAVORITE", favorite.isChecked());
    
            SQLiteOpenHelper starbuzzDatabaseHelper = new StarbuzzDatabaseHelper(this);
            try{
                SQLiteDatabase db = starbuzzDatabaseHelper.getWritableDatabase();
                db.update("DRINK",
                        drinkValues,
                        "_id = ?",
                        new String[] {Integer.toString(drinkId)});
                db.close();
            }catch(SQLiteException e) {
                Toast toast = Toast.makeText(this, "Database unavailable", Toast.LENGTH_SHORT);
                toast.show();
            }
        }
    
        private class UpdateDrinkTask extends AsyncTask<Integer, Void, Boolean> {
            private ContentValues drinkValues;
    
            protected void onPreExecute(){
                CheckBox favorite = (CheckBox) findViewById(R.id.favorite);
                drinkValues = new ContentValues();
                drinkValues.put("FAVORITE", favorite.isChecked());
            }
    
            @Override
            protected Boolean doInBackground(Integer[] drinks) {
                int drinkId = drinks[0];
                SQLiteOpenHelper starbuzzDatabaseHelper = new StarbuzzDatabaseHelper(DrinkActivity.this);
                try {
                    SQLiteDatabase db = starbuzzDatabaseHelper.getWritableDatabase();
                    db.update("DRINK",
                            drinkValues,
                            "_id = ?",
                            new String[] {Integer.toString(drinkId)});
                    db.close();
                    return true;
                }catch (SQLiteException e){
                    return false;
                }
            }
        }
    
        protected void onPostExecute(Boolean success) {
            if (!success) {
                Toast toast = Toast.makeText(DrinkActivity.this, "Darabase unavailable", Toast.LENGTH_SHORT);
                toast.show();
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
  • 相关阅读:
    docker swarm集群部署
    R语言ggplot2可视化:基于aes函数中的fill参数和shape参数自定义绘制分组折线图并添加数据点(散点)、设置可视化图像的主题为theme_gray
    3D全景:为各行业提供更真实的交互体验
    洛谷P5731 【深基5.习6】蛇形方阵java版题解
    word行距怎么设置?专业排版,让文档更具吸引力!
    9.力扣c++刷题-->跳跃游戏
    宏定义_可变参数
    Unity 编辑器常用方法
    大学生旅游风景主题dreamweaver网页设计大作业-陕西渭南HTML+CSS制作网页
    Linux设备驱动
  • 原文地址:https://blog.csdn.net/weixin_44014982/article/details/133689105