Android中第三方框架【网络框架Volley】的使用【Application生命周期】【内存泄漏问题】

本文介绍如何通过自定义Application类实现全局变量管理,并深入探讨内存泄漏问题及其解决方案。同时,提供了使用Volley框架进行网络请求的具体实现,包括图片加载、数据解析等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工作内容:

1.自定义类继承Application类(全局变量的定义——所有activity都可以使用

2.内存泄漏问题分享

3.第三方框架Volley的使用

学习分享:(这里讲解Volley会涉及到子定义Application子类,就先说说Application的使用)

一、application讲解

1.Application生命周期

2.onCreate 在创建利用程序时创建
3.onTerminate 当终止利用程序对象时调用,不保证1定被调用,当程序是被内核终止以便为其他利用程序释放资源,那
么将不会提示,并且不调用利用程序的对象的onTerminate方法而直接终止进 程
4.onLowMemory当后台程序已终止资源还匮乏时会调用这个方法。好的利用程序1般会在这个方法里面释放1些没必要
要的资源来应付当后台程序已终止,前台利用程序内存还不够时的情况。
5.onConfigurationChanged 配置改变时触发这个方法

application 被杀死的情况分析:内存较低的时候杀掉哪一个进程?

1:前端进程可以是1个持有运行在屏幕最前端并与用户交互的Activity的进程(onResume方法被调用时),也能够是持有1个正在运行的IntentReceiver(也就是说他正在履行自己的onReceiveIntent方法)的进程. 在系统中, 只会有少数这样的进程, 并且除非内存已低到不够这些进程运行, 否则系统不会主动杀掉这些进程. 这时候, 装备通常已到达了需要内存整理的状态, 所以杀掉这些进程是为了不让用户界面停止响应.
2:可视进程是持有1个被用户可见, 但没有显示在最前端 (onPause方法被调用时) 的Activity的进程. 举例来讲, 这类进程通常出现在1个前端Activity以1个对话框出现并保持前1个Activity可见时. 这类进程被系统认为是极为重要的, 并且通常不会被杀掉, 除非为了保持所有前端进程正常运行不能不杀掉这些可见进程.
3:服务进程是持有1个Service的进程, 该Service是由startService()方法启动的, 虽然这些进程用户不能直接看到, 但是通常他们做的工作用户是10分关注的(例如, 在后台播放mp3或是在后台下载 上传文件), 所以, 除非为了保持所有的前端进程和可视进程正常运行外, 系统是不会杀掉服务进程的.
4:后台进程是持有1个不再被用户可见的Activity(onStop()方法被调用时)的进程. 这些进程不会直接影响用户体验. 加入这些进程已完全的,正确的完成了自己的生命周期(访问Activity查看更多细节), 系统会在为前3种进程释放内存时随时杀掉这些后台进程. 通常会有很多的后台进程在运行, 所以这些进程被寄存在1个LRU列表中, 以保证在低内存的时候, 最近1个被用户看到的进程会被最后杀掉.
5:空进程是没有持有任何活动利用组件的进程. 保存这类进程的唯1理由是为了提供1种缓存机制, 缩短他的利用下次运行时的启动时间. 就其本身而言, 系统杀掉这些进程的目的是为了在这些空进程和底层的核心缓存之间平衡全部系统的资源. 
当需要给1个进程分类的时候, 系统会在该进程中处于活动状态的所有组件里掉选1个重要等级最高作为分类根据. 查看Activity, Service,和IntentReceiver的文档, 了解每一个组件在进程全部生命周期中的贡献. 每个classes的文档详细描写他们在各自利用的生命周期中所起得作用.

public class MyApplication extends Application {
    private static Gson gson;
    private static RequestQueue requestQueue;
    private static HashMap<String,Object> datas;//常用于存放数据[例如在Acitivity]
    /**
     * Application也有自己的生命周期(不能写构造函数)
     * 生命周期:
     *     onCreate()   程序创建的时候执行
     *     onTerminate()  程序终止时执行
     *     onLowMemory()  低内存时执行
     *     onTrimMemory()   程序内存清理时执行
     *     onConfigurationChanged()  配置改变时执行
     */
    @Override
    public void onCreate() {
        super.onCreate();
        this.gson = new Gson();
        this.requestQueue = Volley.newRequestQueue(getApplicationContext());
    }
    public static Gson getGson() {
        return gson;
    }

    public static RequestQueue getRequestQueue() {
        return requestQueue;
    }
    //退出程序时执行
    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
    }
}

二、内存泄漏问题分享(MemoryLeak

在Java中内存泄漏是只,某个(某些)对象已不在被使用应当被gc所回收,但有1个对象持有这个对象的援用而禁止这个对象被回收(例如:public static修饰的属性)。

常常致使内存泄漏核心缘由: keeping a long-lived reference to a Context.持有1个context的对象,从而gc不能回收。

1.1个View的作用域超越了所在的Activity的作用域,比如1个static的View或把1个View cache到了application当中 etc理解:内存:注意静态的数据和缓存中的数据;注意释放;
2.某些与View关联的Drawable的作用域超越了Activity的作用域
3.Runnable对象:比如在1个Activity中启用了1个新线程去履行1个任务,在这期间这个Activity被系统回收了, 但Runnalbe的 任务还没有履行终了并持有Activity的援用而泄漏,但这类泄漏1般来泄漏1段时间,只有Runnalbe的线程履行完闭,这个 Activity又可以被正常回收了。
4.内存类的对象作用域超越Activity的范围:比如定义了1个内存类来存储数据,又把这个内存类的对象传给了其它Activity 或Service等。由于内部类的对象会持有当前类的援用,所以也就持有了Context的援用。解决方法是如果不需要当前的援用把内部类写成static或,把内部类抽取出来变成1个单独的类,或把避免内部对象作用域超越Activity的作用域。out Of Memery Error 在android中每个程序所分到的内存大小是有限的,如果超过了这个数就会报Out Of Memory Error。 android给程序分配的内存大小与手机硬件有关,以下是1些手机的数据:
G1:16M Droid:24 Nexus One:32M Xoom:48Ms
所以尽可能把程序中的一些大的数据cache到本地文件。以避免内存使用量超标。
记得数据传递完成以后,把寄存在application的HashMap中的数据remove掉
,以避免产生内存的泄漏

三、第三方框架Volley的使用

1.导入Volley到项目(将网上下载的Volley粘贴到项目的lib目录下→add as libs

2.使用Volley获取网络数据(JSON,Bitmap)

3.写一个VolleyUtil工具类【RequestQueue requestQueue = Volley.newRequestQueue(Context);】

import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.ImageView;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.self.test.MyApplication;
import com.self.test.R;
import com.self.test.util.LogD;
import com.self.test.util.ToastUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by 刘世华 on 2017/7/5 0005.
 * Discription :
 */

public class VolleyUtil {
    private final int size = (int) Runtime.getRuntime().maxMemory();
    /**
     * 生成缓存对象
     * 申请RAM空间最大是(手机RAM/7)【在内部类MyImageCache的中调用】
     */
    private LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(size / 7) {
        @Override
        protected int sizeOf(String key, Bitmap value) {
            return value.getByteCount();
        }
    };
    private final Gson gson = new Gson();
    private RequestQueue requestQueue = MyApplication.getRequestQueue();
    private VolleyCallView callView;

    public VolleyUtil(VolleyCallView callView) {
        this.callView = callView;

    }

    /**
     * 对外接口(Activity中调用)
     * 获取网络数据方法
     *
     * @param urlString
     */
    public void getData(final Context context, String urlString) {
        /**
         * 参数 1 请求方式(类似GET,POST) Request.Method.GET
         * 参数 2 请求网址
         * 参数 3 监听后台获取数据操作是否完成,返回执行完得到的String
         * 参数 4 监听请求错误,返回错误信息
         */
        StringRequest request = new StringRequest(Request.Method.GET, urlString, new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                /**
                 * Ui线程执行
                 * 后台执行完成,返回值是s【是一个JSON数据】
                 */
                LogD.d("返回数据:" + s);
                ResultEntity result = gson.fromJson(s, ResultEntity.class);//用gson解析成实体类
                if (result != null && result.getError_code() == 0) {//判定获取成功
                    callView.loadOk(result);
                } else {
                    ToastUtil.show(context, "请求出错:" + s);
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                ToastUtil.show(context, "请求出错:" + volleyError.getMessage());
            }
        })
//        {
//            /**
//             * 对应方法:(应用与baidustore中的api)
//             * connection.setRequestProperty("apikey","1b003ee9be62dfbef84e61ff07f54bc2");
//             * api没要求则不需要
//             * @return
//             * @throws AuthFailureError 验证失败错误
//             */
//            @Override
//            public Map<String, String> getHeaders() throws AuthFailureError {
//                Map<String, String> map = new HashMap<>();
//                map.put("apikey", "4d3e52e213414983b7e28d92def2738a");
//                return map;
//            }
//        }
                ;
        request.setTag(urlString);
        requestQueue.add(request);
    }

    /**
     * adapter中getView方法调用
     * 对外接口【图片url,缓存到RAM中,从缓存中获取bitmap】
     *
     * @param urlString 图片url
     * @param imageView 给这个ImageView添加图片(图片加载完成后)
     */
    public void getImageFromImageLoader(String urlString, ImageView imageView) {
        ImageLoader imageLoader = new ImageLoader(MyApplication.getRequestQueue(), new MyImageCache());
        /**
         * 参数一:imageView 来自adapter
         * 参数二:得到为空时的默认设置图片
         * 参数三:获取失败时设置图片
         */
        ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
        imageLoader.get(urlString, listener);
    }

    //图片缓存类【会用到缓存对象】
    class MyImageCache implements ImageLoader.ImageCache {
        /**
         * 获取缓存中的bitmap
         *
         * @param s 键
         * @return s = (new StringBuilder(url.length() + 12)).append("#W")
         * .append(maxWidth).append("#H").append(maxHeight).append(url).toString();
         */
        @Override
        public Bitmap getBitmap(String s) {
            Log.d("-----------", "缓存获取");
            return lruCache.get(s);
        }

        /**
         * 将图片bitmap放入缓存
         *
         * @param s      键(与get方法中一样)
         * @param bitmap 值
         */
        @Override
        public void putBitmap(String s, Bitmap bitmap) {
            lruCache.put(s, bitmap);
        }
    }
}

Activity代码:这里用了butterknife,具体用法网上很多哈

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.self.test.R;
import com.self.test.util.LogD;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class VolleyTestActivity extends AppCompatActivity implements VolleyCallView {
    @BindView(R.id.showText)
    TextView showText;
    private VolleyUtil util;
    private StringBuffer buffer;
    private int page = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_volley_test);
        ButterKnife.bind(this);
        util = new VolleyUtil(this);//将回调接口的实现类传入util中
        buffer = new StringBuffer();
    }

    @Override
    public void loadOk(ResultEntity resultEntity) {//返回的数据
        buffer = new StringBuffer();
        if (resultEntity != null && resultEntity.getResult() != null && resultEntity.getResult().size() > 0) {
            for (int i = 0; i < resultEntity.getResult().size(); i++) {
                ResultEntity.ResultBean bean = resultEntity.getResult().get(i);
                buffer.append(bean.getAddress() + "\n");
            }
            showText.setText(buffer.toString());//用textView展示出来
        }
    }

    @OnClick(R.id.load)
    public void onClick() {//点击加载数据按钮
        loadData();
        page++;//每次请求的页数+1;
    }

    /**
     * 加载数据
     */
    private void loadData() {
        String baseUrl = "http://api.avatardata.cn/PostNumber/QueryPostnumber?" +
                "key=4d3e52e213414983b7e28d92def2738a&postnumber=030006&page=%s&rows=15";
        String url = String.format(baseUrl, page);//得到请求的url
        //上面这句得到的是:http://api.avatardata.cn/PostNumber/QueryPostnumber?key=4d3e52e213414983b7e28d92def2738a&postnumber=030006&page=1&rows=15
        util.getData(this, url);
    }
}

adapter中调用:【加载图片】

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
    ViewHolder myHolder = (ViewHolder)holder;
    /**
     * 调用ImgLoadUtilgetBitmapfromUrl方法
     * volleyUtil是一个成员变量
     */
    volleyUtil.getImageFromImageLoader(list.get(position).getPicUrl(),myHolder.imageView);
    myHolder.tvTitle.setText(list.get(position).getTitle());
    myHolder.imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            recylerItemClickListener.RecylerItemClick(v,position);
        }
    });
}

ResultEntiy返回的实体类【用gsonformat直接将返回实体类转成代码】

import java.util.List;

/**
 * Created by 刘世华 on 2017/7/5 0005.
 * Discription : 
 */

public class ResultEntity {

    private int total;
    private Object SingerResult;
    private int error_code;
    private String reason;
    private List<ResultBean> result;

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public Object getSingerResult() {
        return SingerResult;
    }

    public void setSingerResult(Object SingerResult) {
        this.SingerResult = SingerResult;
    }

    public int getError_code() {
        return error_code;
    }

    public void setError_code(int error_code) {
        this.error_code = error_code;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public List<ResultBean> getResult() {
        return result;
    }

    public void setResult(List<ResultBean> result) {
        this.result = result;
    }

    public static class ResultBean {
        /**
         * postnumber : 030006
         * province : 山西省
         * city : 太原市
         * district : 小店区
         * address : 坞城西街
         * jd : 山西省太原市小店区
         */

        private String postnumber;
        private String province;
        private String city;
        private String district;
        private String address;
        private String jd;

        public String getPostnumber() {
            return postnumber;
        }

        public void setPostnumber(String postnumber) {
            this.postnumber = postnumber;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getDistrict() {
            return district;
        }

        public void setDistrict(String district) {
            this.district = district;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public String getJd() {
            return jd;
        }

        public void setJd(String jd) {
            this.jd = jd;
        }
    }
}
回调接口
public interface VolleyCallView {
    void loadOk(ResultEntity resultEntity);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值