11月11日Android学习笔记

标签

Android

Thread

AsyncTask

Notification

发布时间:

本文字数:2,028 字 阅读完需:约 5 分钟

Android 异步任务

InfoAsyncTask.java

package com.xyl.app1111;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;

import com.xyl.app1111.utils.HttpUtils;

public class InfoAsyncTask extends AsyncTask<String, Void, String> {

    private Context context;
    private ProgressDialog dialog;
    public interface OnLoadDataListener{
        public void onSuccess(String json);
        public void onError();
    }
    private OnLoadDataListener onLoadDataListener;
    public void setOnLoadDataListener(OnLoadDataListener onLoadDataListener){
        this.onLoadDataListener = onLoadDataListener;
    }

    public InfoAsyncTask(Context context) {
        this.context = context;
    }

    /**
     * 在子线程开启之前被调用,运行在主线程当中,通常做进度对话框的初始化工作
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        dialog = new ProgressDialog(context);
        dialog.setMessage("正在加载中,请稍后");
        dialog.show();
    }

    /**
     * 开启线程,进行耗时操作
     * @param params
     * @return
     */
    @Override
    protected String doInBackground(String... params) {
        String s = HttpUtils.getStringByConnection(params[0]);
        return s;
    }

    /**
     * 计算下载的进度,在此处更新进度条
     * @param values
     */
    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
    }

    /**
     * 运行在主线程当中,将耗时操作的结果以参数的形式显示在参数当中,result为doInBackground的返回值
     * @param result
     */
    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        dialog.dismiss();
        if (onLoadDataListener!=null) {
            if (!TextUtils.isEmpty(result)) {
                onLoadDataListener.onSuccess(result);
            }
            else{
                onLoadDataListener.onError();
            }
        }
    }
}

异步请求底层模拟

package com.animee.app1111.utils;


import android.os.Handler;
import android.os.Message;

import androidx.annotation.NonNull;

/**
 * 作者:animee on 2022/11/11 09:51
 */
public abstract  class AnimeeTask<T,M> {

    protected void onPreExecute(){

    }
    protected abstract M doInBackground(T...params);
    protected void onPostExecute(M result){

    }

    public AnimeeTask(){
        onPreExecute();
    }

    public void execute(T...value){
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                M m = doInBackground(value);
                //Message对象获取方法有三个
                Message msg = Message.obtain();
                msg.what = 1;
                msg.obj = m;
                handler.sendMessage(msg);

            }
        });
        thread.start();
    }
    Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            if (msg.what==1) {
                M m = (M) msg.obj;
                onPostExecute(m);
            }
            return false;
        }
    });
}

知识点

1.android处理网络请求等耗时操作的方法,有两种:
  1.异步任务   AsyncTask
  2.多线程和线程池    Handler

2.为什么要使用异步任务?
      1.Android是一个单线程模型,同时也是一个多线程操作系统。
    2.把耗时操作(读取文件,加载网络请求)放到子线程当中执行。
原因:android只能在主线程当中更新ui,即UI线程,不能在其他线程当中做更新ui的操作。
这样保证了程序的稳定性和准确性。
稳定性:避免了多线程同时操作ui,造成了线程混乱。
准备性:把耗时操作都放到子线程当中执行,就会避免了ANR(Android Not Responding)应用程序无响应异常。

3.AsyncTask为何而生?
       1.可以封装,简化异步操作
       2.获取网络数据,传递给主线程更新UI。

4.构建AsyncTask子类的参数、
AsyncTask<params,progress,result>是一个抽象类。
通常用于被继承,继承这个asyncTask就需要指定三个泛型参数。
    Params:启动任务时输入参数的类型
    Progress:后台任务执行中返回进度值的类型
    Result: 后台任务执行完返回结果的类型。

5.继承AsyncTask当中需要重写的四个方法。

onPreExecute():后台操作前被调用,主要用于一些UI组件的初始化。(不做耗时操作)
doInBackground(Params...):必须重写,异步任务要执行的操作必须在这个方法中执行。(执行耗时操作)
onPostExecute(Result):在doInBackground方法执行完成后,自动调用此方法,同时doInBackground方法返回的数据
            会作为此方法的参数。一般在此方法中去执行更新ui的操作。
onProgressUpdate(Progress...):更新了任务执行就进度后,会触发的方法。在doInBackground方法当中调用
                publishProgress(Progress...)方法,此方法才会被系统调用。


6.AsyncTask的具体实现过程。
      1.写一个类,继承asyncTask,同时传入指定的三个泛型
    2.重写必要的两个方法。
            doInBackground();
        onPostExecute();
    3.重写可选的两个方法。
            onPreExecute();
        onProgressUpdate();
    4.在ui线程当中实例化,自定义的子类的对象。
    5.在ui线程当中,把asynctask的对象去执行execute的方法,就是执行了异步任务。


7.ScrollView  :  滚动组件
  父类是:Framelayout
   内部只能包含一个子类控件,通常这个控件是LinearLayout,可以在线性布局当中去放置其他控件。

8、android的view有一个表示显示状态的属性visibility。
  对应的值有三个:
   visible:设置控件可见
   invisible:设置控件不可见
   gone:设置控件隐藏
   invisible和gone的主要区别:当设置为invisible时,界面保留view控件所占据的空间。
   当设定为gone时,view隐藏并且不保留view控件所占据的空间。

9.AsyncTask的不足之处。
     1.AsyncTask如果在同一个界面当中加载很多接口,会开启大量的线程,会导致系统资源严重被占用,
      然后就会产生应用程序FC错误。(FC:应用程序强制关闭,崩溃)
   2.AsyncTask执行doinBackground方法时,即使调用了取消方法,也不能取消,要等到doinBackground
   方法中的代码执行结束后才能取消。
   3.线程池是不能维护的,当产生大量异步操作的时候线程池就满了,然后就会产生异常。

10.异步和同步
     同步:在同一个线程当中执行一系列的操作。
   异步:多个线程当中完成工作,最后通过多线程通信达到最终效果。

11.AsyncTask的取消。
     1.要在UI线程当中执行AsyncTask的cancel方法。
   2.要在doInBackground方法当中做一个判断,判断条件是是否被取消isCancelled(),如果未被取消才执行逻辑代码。
   3.cancel(true)   :只要是执行了这个方法,AsyncTask立即被取消。
     cancel(false)  : 执行了这个方法,要等本次while中的内容执行完才被取消。

12.AsyncTask的注意事项:
      1.必须在UI线程当中创建AsyncTask的实例。
    2.必须在ui线程当中执行AsyncTask的execute的方法。
    3.重写的四个方法是系统自动调用的,我们不能手动的调用。
    4.每个asyncTask的实例只能被执行一次,多次执行就会出现异常。

滚动分页加载

   //ListView 滚动监听接口
    AbsListView.OnScrollListener listener = new AbsListView.OnScrollListener() {
        // 当滚动状态发生改变时,回调的方法
//        SCROLL_STATE_IDLE 停止状态  SCROLL_STATE_TOUCH_SCROLL 手指触摸滚动
//        SCROLL_STATE_FLING 惯性滚动
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (scrollState == SCROLL_STATE_IDLE
                    && lastVisibleItem==adapter.getCount()) {
                //显示尾布局,并且开始加载
                footerView.setVisibility(View.VISIBLE);
                page++;
                String url = creatURL();
                loadDatas(url);
            }
        }
        //    firstVisibleItem:当前可见第一条的位置   visibleItemCount 可见条目数量   totalItemCount 一共有多少条
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            lastVisibleItem = firstVisibleItem+visibleItemCount-1;
        }
    };

下拉刷新

build.gradle

    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"

使用

    binding.srLayout.setColorSchemeColors(Color.RED);
    binding.srLayout.setOnRefreshListener(onRefreshListener);
    //    下拉刷新的监听接口
    SwipeRefreshLayout.OnRefreshListener onRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            page=1;
            String url = creatURL();
            mDatas.clear();
            loadDatas(url);
        }
    };

通知(Notification)

发送简单通知

    /**
     * 发送简单通知
     */
    private void sendNormalNotify() {
        //创建通知的装饰对象
        Notification.Builder builder = new Notification.Builder(this);
        //设置通知显示内容
        builder.setContentTitle("好消息, 好消息!!!!");
        builder.setContentText("新冠疫情神奇消失了。。。");
        builder.setSmallIcon(R.mipmap.ib_luck_normal);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.jinniu);
        builder.setLargeIcon(bitmap);
        builder.setAutoCancel(true);
        builder.setOngoing(false);//侧滑能不能取消通知
        builder.setPriority(Notification.PRIORITY_HIGH);
        builder.setTicker("放心Go向你发来了双11问候,快来看我.....");
        //设置点击预先跳转意图
        Intent intent = new Intent(this, NewsInfoActivity.class);
        builder.setContentIntent(PendingIntent.getActivity(this, 100, intent, PendingIntent.FLAG_ONE_SHOT));
        //获取通知对象
        Notification notification = builder.build();
        //发送通知
        manager.notify(1, notification);
    }

完整实例

注意: Andorid

import androidx.appcompat.app.AppCompatActivity;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.view.View;

/**
 * Notification  通知信息
 * 在应用中如果需要提示用户一些信息,显示在通知栏,可以发送Notification
 *
 * */
public class NotifyActivity extends AppCompatActivity {

    NotificationManager manager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_notify);
        manager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        createChannel();

    }
    private final String CHANNEL_ID = "com.animee.app1111";
    //渠道名
    private final String CHANNEL_NAME = "渠道名-简单通知";
    //渠道重要级
    private final int CHANNEL_IMPORTANCE = NotificationManager.IMPORTANCE_DEFAULT;
    private void createChannel() {
        //创建通知渠道,Android8.0及以上需要
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            return;
        }
        NotificationChannel notificationChannel = new NotificationChannel(
                CHANNEL_ID, CHANNEL_NAME, CHANNEL_IMPORTANCE);
        manager.createNotificationChannel(notificationChannel);
    }
    public void onClick(View view) {

        switch (view.getId()) {
            case R.id.notify_btn1:
                sendNormalNotify();
                break;
        }
    }
    /** 发送简单通知*/
    private void sendNormalNotify() {
//        创建通知的装饰对象
        Notification.Builder builder = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            builder = new Notification.Builder(this, CHANNEL_ID);
        }
        else{
            builder = new Notification.Builder(this);
        }
//        设置通知显示内容
        builder.setContentTitle("好消息,好消息!!!");
        builder.setContentText("新冠疫情神奇消失了.......");
        builder.setSmallIcon(R.mipmap.ic_launcher);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.jinniu);
        builder.setLargeIcon(bitmap);

        builder.setAutoCancel(true);
        builder.setOngoing(false);    //侧滑能不能取消通知
        builder.setPriority(Notification.PRIORITY_HIGH);
        builder.setTicker("放心Go向你发来了双11问候,快来看我......");
//        设置点击预先跳转意图
        Intent intent = new Intent(this, NewsInfoActivity.class);

        builder.setContentIntent(PendingIntent
                .getActivity(this,100,intent,PendingIntent.FLAG_IMMUTABLE));
//      获取通知对象
        Notification notification = builder.build();

//        发送通知
        manager.notify(1,notification);
    }



}

发送大图通知

 private void sendBigImgNotify() {
        NotificationCompat.Builder builder
                = new NotificationCompat.Builder(this);
        NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
        Bitmap bm1 = BitmapFactory.decodeResource(getResources(), R.mipmap.jinniu);
        style.bigLargeIcon(bm1);
        style.setBigContentTitle("美图来袭.....");
        style.setSummaryText("每日壁纸更新更多内容,点击查看");
        builder.setStyle(style);
        builder.setShowWhen(true);
        //必须设置小图标
        builder.setSmallIcon(R.mipmap.ib_luck_normal);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            builder.setChannelId(CHANNEL_ID);
        }
        Notification nf = builder.build();
        manager.notify(2, nf);
    }

发送多条消息通知

    private void sendListNotify() {
        //        创建通知的装饰对象
        Notification.Builder builder = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            builder = new Notification.Builder(this, CHANNEL_ID);
        }
        else{
            builder = new Notification.Builder(this);
        }
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setContentTitle("今日卫健委发出通告");
        Notification.InboxStyle style = new Notification.InboxStyle();
        style.addLine("取消健康码");
        style.addLine("取消隔离");
        style.addLine("取消核酸检测");
        builder.setStyle(style);
        Notification notify = builder.build();
        manager.notify(3, notify);
    }