黑马程序员技术交流社区

标题: 【济南中心】Android课程同步笔记智慧北京:Day05(上) [打印本页]

作者: 小鲁哥哥    时间: 2017-6-4 11:13
标题: 【济南中心】Android课程同步笔记智慧北京:Day05(上)
本帖最后由 小鲁哥哥 于 2017-6-4 11:18 编辑

【济南中心】Android课程同步笔记智慧北京:Day05(上)

缓存工具类
保存:
从服务器获取数据,把数据保存到/data/data/packagename/files文件中,
以这次请求的url通过md5加密之后作为唯一的文件名,保存到本地

读取:
通过md5加密之后的文件名,从本地读取文件,转换为json数据。


保存数据
[Java] 纯文本查看 复制代码
//缓存json
public static void saveCache(Context context,String url,String json) throws  Exception{
    //文件名
    String name = Md5Utils.encode(url);
    //输出流
    FileOutputStream fileOutputStream = context.openFileOutput(name, Context.MODE_PRIVATE);
    //写数据
    fileOutputStream.write(json.getBytes());
    //关流
    fileOutputStream.close();;
}
读取数据
[Java] 纯文本查看 复制代码
//读取json
public static String readCache(Context context,String url)throws  Exception{
    //文件名
    String name = Md5Utils.encode(url);
    FileInputStream fileInputStream = context.openFileInput(name);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len = 0;
    while((len = fileInputStream.read(buffer)) != -1){
        bos.write(buffer,0,len);
    }
    String json = bos.toString();
    bos.close();
    fileInputStream.close();
    return json;
}
缓存网络数据
新闻中心模块缓存处理
加载数据成功:
加载数据失败:
组图模块缓存数据

加载数据成功以后缓存数据:
加载数据失败读取缓存数据:
轮播图模块

成功:
失败:

切换Tab页面避免重新加载数据

默认情况下MainActivity中每次切换tab都会加载数据如下代码
[Java] 纯文本查看 复制代码
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
    int item = 0;
    switch (checkedId){
        case R.id.rb_home:
            item = 0;
            slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);//无法滑出侧滑菜单
            break;
        case R.id.rb_newscener:
            item = 1;
            slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
            break;
        case R.id.rb_smartservice:
            item = 2;
            slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
            break;
        case R.id.rb_govaffairs:
            item = 3;
            slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
            break;
        case R.id.rb_setting:
            item = 4;
            slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);
            break;
    }
    //让上面的ViewPager切换到对应的页面
    tabVp.setCurrentItem(item,false);

    //加载网络数据的入口
    BaseFragment baseFragment = (BaseFragment) fragments.get(item);
    if(baseFragment instanceof BaseLoadNetDataOperator){
        ((BaseLoadNetDataOperator) baseFragment).loadNetData();
    }
}

禁止每次都去加载数据
在我们每个Fragment的父类BaseFragment定义个boolean类型的标示默认为false当数据加载成功以后设置true,baseFragment定义一个标示
[Java] 纯文本查看 复制代码
public boolean hasLoadData;
在对应的Fragment中,成功加载数据以后,把hasLoadData设置为true
比如新闻中心的Fragment:NewsCenterFragment
MainAcitivity添加是否加载过网络数据的标示判断
[Java] 纯文本查看 复制代码
//获取到对应的Fragment页面
BaseFragment baseFragment = (BaseFragment) fragments.get(item);
if(baseFragment instanceof BaseLoadNetDataOperator && !baseFragment.hasLoadData){
    BaseLoadNetDataOperator baseLoadNetDataOperator = (BaseLoadNetDataOperator) baseFragment;
    baseLoadNetDataOperator.loadNetData();
}

切换多个Fragment时, NewsCenterFragment无法正常加载数据
由于ViewPager有预加载机制默认它会预加载三个Fragment,如果超出了,就会回收之前创建的Fragment始终保留三个Fragment。需要ViewPager缓存5个页面。在我们的MainActivity中的initViewpager方法中设置缓存5个界面。
注意ViewPager的setOffscreenPageLimit(5),如果指定的数值为5,ViewPager会缓存当前Fragment左右各5Fragment。这是ViewPager的预加载机制


点击新闻条目进入新闻详情页

给新闻条目添加点击事件
在我们的NewsListAdapter类中onBindViewHolder处理点击事件
[Java] 纯文本查看 复制代码
//条目点击事件
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //跳转到新闻详情界面
        Intent intent = new Intent(context,NewsDetailActivity.class);
        intent.putExtra("url",newsBean.url);
        context.startActivity(intent);
    }
});
创建NewsDeatailActiity
布局实现
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/title_red_bg">

        <ImageButton
            android:id="@+id/ib_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/back"
            android:layout_marginLeft="10dp"
            android:layout_centerVertical="true"/>
        <ImageButton
            android:id="@+id/ib_textsize"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon_textsize"
            android:layout_toLeftOf="@+id/ib_share"
            android:layout_marginRight="5dp"
            android:layout_centerVertical="true"/>
        <ImageButton
            android:id="@+id/ib_share"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon_share"
            android:layout_alignParentRight="true"
            android:layout_marginRight="10dp"
            android:layout_centerVertical="true"/>
    </RelativeLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <WebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"></WebView>
        <ProgressBar
            android:id="@+id/pb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:indeterminateDrawable="@drawable/pb_bg"
            android:layout_gravity="center"/>
    </FrameLayout>

</LinearLayout>

加载显示新闻详情

WebView加载网页结束隐藏进度条


WebView支持js脚本


修改Webview字体的大小
创建对话框让用户去选择字体的大小初始化字体型号数组
[Java] 纯文本查看 复制代码
private String[] types = new String[]{
        "超大号字体",
        "大号字体",
        "正常字体",
        "小号字体",
        "超小号字体",
};

private WebSettings.TextSize[] textSizes = new WebSettings.TextSize[]{
        WebSettings.TextSize.LARGEST,
        WebSettings.TextSize.LARGER,
        WebSettings.TextSize.NORMAL,
        WebSettings.TextSize.SMALLER,
        WebSettings.TextSize.SMALLEST,
};

创建对话框并弹出对话框

选择字体型号修改网页字体大小


ShareSdk分享

ShareSDK使用
1. 下载ShareSDK
2. 运行SDK工具,生成项目包,进行覆盖
3. 查看Android文档
4. 创建应用, 生成appkey,替换项目中的appkey
5. 拷贝相关权限和代码
6. 注意sdcard根目录下需要有test.jpg这张图片,否则会分享失败
7. 运行程序,进行测试
8. 可以修改主题样式
启动分享功能
[Java] 纯文本查看 复制代码
private void showShare() {
        ShareSDK.initSDK(this);
        OnekeyShare oks = new OnekeyShare();
        //关闭sso授权
        oks.disableSSOWhenAuthorize();

        // 分享时Notification的图标和文字  2.5.9以后的版本不调用此方法
        //oks.setNotification(R.drawable.ic_launcher, getString(R.string.app_name));
        // title标题,印象笔记、邮箱、信息、微信、人人网和QQ空间使用
        oks.setTitle("黑马程序员分享的");
        // titleUrl是标题的网络链接,仅在人人网和QQ空间使用
        oks.setTitleUrl("http://sharesdk.cn");
        // text是分享文本,所有平台都需要这个字段
        oks.setText("我是黑马程序员,我骄傲!");
        //分享网络图片,新浪微博分享网络图片需要通过审核后申请高级写入接口,否则请注释掉测试新浪微博
        oks.setImageUrl("http://f1.sharesdk.cn/imgs/2014/02/26/owWpLZo_638x960.jpg");
        // imagePath是图片的本地路径,Linked-In以外的平台都支持此参数
        //oks.setImagePath("/sdcard/test.jpg");//确保SDcard下面存在此张图片
        // url仅在微信(包括好友和朋友圈)中使用
        oks.setUrl("http://sharesdk.cn");
        // comment是我对这条分享的评论,仅在人人网和QQ空间使用
        oks.setComment("我是测试评论文本");
        // site是分享此内容的网站名称,仅在QQ空间使用
        oks.setSite(getString(R.string.app_name));
        // siteUrl是分享此内容的网站地址,仅在QQ空间使用
        oks.setSiteUrl("http://sharesdk.cn");

// 启动分享GUI
        oks.show(this);
    }

自定义分享来源
在资产目录下,进行文件配置渠道来源
[XML] 纯文本查看 复制代码
<ShareSDK 
    AppKey = "17965efb617e6"/> <!-- 修改成你在sharesdk后台注册的应用的appkey"-->

<!-- ShareByAppClient标识是否使用微博客户端分享,默认是false -->
<SinaWeibo
    Id="1"
    SortId="1"
    AppKey="568898243"
    AppSecret="38a4f8204cc784f81f9f0daaf31e02e3"
    RedirectUrl="http://www.sharesdk.cn"
    ShareByAppClient="true"
    Enable="true" />
点击的新闻条目变灰

点击条目变化的原理
点击新闻条目时
l 获取该条目新闻的唯一ID:
l sp中得到存储的多个新闻ID的字符串
l 判断字符串是否包含该新闻ID
n 不包含,存储到sp中,刷新界面,更改选中条目的样式
n 如果存在,直接跳转到新闻详情页
点击条目的处理
代码实现:
[Java] 纯文本查看 复制代码
//条目点击事件
    viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //跳转到新闻详情界面
            Intent intent = new Intent(context,NewsDetailActivity.class);
            intent.putExtra("url",newsBean.url);
            context.startActivity(intent);

            //存储该条新闻的唯一标识:
            String id = newsBean.id;
            //存储在哪里?Sp   File   DB()
            String readNews = SPUtils.getString(context, Constant.KEY_HAS_READ,"");
            if(!readNews.contains(id)){
                String value = readNews+ "," + id;
                //存储
                SPUtils.saveString(context,Constant.KEY_HAS_READ,value);
                //刷新界面
                //notifyDataSetChanged();
                viewHolder.tvTitle.setTextColor(Color.GRAY);
            }
        }
    });
}
显示新闻列表时判断是否已经查看过
[Java] 纯文本查看 复制代码
//判断每条新闻是否已经被查看过,如果查看,修改字体样式为灰色
String readNewsContent = SPUtils.getString(context, Constant.KEY_HAS_READ,"");
if(readNewsContent.contains(newsBean.id)){
    viewHolder.tvTitle.setTextColor(Color.GRAY);
}else{
    viewHolder.tvTitle.setTextColor(Color.BLACK);
}

在新闻中心子tab的切换会多出轮播图bug修复
修改多次添加轮播图到头布局中的问题


拽下轮播图后轮播图停止切换的bug修复
下拉加载数据完成以后,手动开始轮播图进行轮播

注意这里不管加载失败和加载成功都要手动的开启轮播图进行轮播图

三级缓存的概念
一级缓存:内存缓存
        当去加载图片时首先从内存缓存查找图片
        :直接显示图片
        没有从二级缓存中查找图片
二级缓存磁盘缓存
        一级缓存没有从二级缓存中查找
        先保存内存缓存中然后显示图片
        没有从三级缓存中获取图片
三级缓存网络缓存
        二级缓存没有图片,从网络缓存中取出图片
        ,磁盘缓存,内存缓存
        没有网络获取图片,然后磁盘缓存,内存缓存显示图片

网络缓存加载图片
编写网络缓存工具类
[Java] 纯文本查看 复制代码
NetCacheUtils:

public class NetCacheUtils {

    private static final String TAG = "NetCacheUtils";
    private Context context;
    //从网络获取图片
    public void getBitmapFromNet(Context context,ImageView iv, String url){
        this.context = context;
        //异步操作
        new BitmapTask().execute(iv,url);
    }

    //异步任务
    class BitmapTask extends AsyncTask<Object,Void,Bitmap>{

        private ImageView iv;
        private String url;

        @Override
        protected Bitmap doInBackground(Object... params) {
            //获取参数
            iv = (ImageView) params[0];
            url = (String) params[1];

            //下载图片
            Bitmap bitmap = downloadBitmap(url);
            MyLogger.i(TAG,"从网络上加载了图片");
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            //获取ImageView对应的url
            String url = (String) iv.getTag();
            if(bitmap != null && this.url.equals(url)){
                iv.setImageBitmap(bitmap);
            }
        }
    }

    //下载图片
    private Bitmap downloadBitmap(String url) {
        Bitmap bitmap = null;
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(6000);
            conn.connect();
            int responseCode = conn.getResponseCode();
            if(responseCode == 200){
                InputStream inputStream = conn.getInputStream();
                //把流转换成Bitmap对象
                bitmap = BitmapFactory.decodeStream(inputStream);
                return bitmap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(conn != null){
                conn.disconnect();
            }
        }
        return bitmap;
    }
}

异步任务加载网络图片
[Java] 纯文本查看 复制代码
//异步任务
class BitmapTask extends AsyncTask<Object,Void,Bitmap>{

    private ImageView iv;
    private String url;

    @Override
    protected Bitmap doInBackground(Object... params) {
        //获取参数
        iv = (ImageView) params[0];
        url = (String) params[1];

        //下载图片
        Bitmap bitmap = downloadBitmap(url);
        MyLogger.i(TAG,"从网络上加载了图片");
        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        //获取ImageView对应的url
        String url = (String) iv.getTag();
        if(bitmap != null && this.url.equals(url)){
            iv.setImageBitmap(bitmap);
        }
    }
}

网络加载图片
[Java] 纯文本查看 复制代码
//下载图片
private Bitmap downloadBitmap(String url) {
    Bitmap bitmap = null;
    HttpURLConnection conn = null;
    try {
        conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(3000);
        conn.setReadTimeout(6000);
        conn.connect();
        int responseCode = conn.getResponseCode();
        if(responseCode == 200){
            InputStream inputStream = conn.getInputStream();
            //把流转换成Bitmap对象
            bitmap = BitmapFactory.decodeStream(inputStream);
            return bitmap;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if(conn != null){
            conn.disconnect();
        }
    }
    return bitmap;
}

执行异步任务
[Java] 纯文本查看 复制代码
//从网络获取图片
public void getBitmapFromNet(Context context,ImageView iv, String url){
    this.context = context;
    //异步操作
    new BitmapTask().execute(iv,url);
}

网络缓存加载图片-图片错位
解决图片错误问题:imageview设置一个tag
[Java] 纯文本查看 复制代码
    //从网络获取图片
    public void getBitmapFromNet(Context context,ImageView iv, String url){
        this.context = context;
        //让ImageView和url关联起来
        iv.setTag(url);
        //异步操作
        new BitmapTask().execute(iv,url);
    }

显示图片时对比URL地址
[Java] 纯文本查看 复制代码
@Override
protected void onPostExecute(Bitmap bitmap) {
    super.onPostExecute(bitmap);
    //获取ImageView对应的url
    String url = (String) iv.getTag();
    if(bitmap != null && this.url.equals(url)){
        iv.setImageBitmap(bitmap);
    }
}

磁盘缓存
写缓存到磁盘
[Java] 纯文本查看 复制代码
//写缓存
public static void saveCache(Context context,Bitmap bitmap, String url){
    //缓存目录
    File dir = new File(context.getCacheDir(),"zhbj_cache");
    if(!dir.exists()){
        dir.mkdirs();
    }

    //把图片缓存在缓存目录
    File file = new File(dir, Md5Utils.encode(url));
    FileOutputStream stream = null;
    try {
        stream = new FileOutputStream(file);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream);
}

从磁盘中读缓存
[Java] 纯文本查看 复制代码
//写缓存
public static void saveCache(Context context,Bitmap bitmap, String url){
    //缓存目录
    File dir = new File(context.getCacheDir(),"zhbj_cache");
    if(!dir.exists()){
        dir.mkdirs();
    }

    //把图片缓存在缓存目录
    File file = new File(dir, Md5Utils.encode(url));
    FileOutputStream stream = null;
    try {
        stream = new FileOutputStream(file);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream);
}

修改网络缓存逻辑
当从网络中获取图片,应该缓存到磁盘中
[Java] 纯文本查看 复制代码
class BitmapTask extends AsyncTask<Object,Void,Bitmap>{

    private ImageView iv;
    private String url;

    @Override
    protected Bitmap doInBackground(Object... params) {
        //获取参数
        iv = (ImageView) params[0];
        url = (String) params[1];

        //下载图片
        Bitmap bitmap = downloadBitmap(url);
        MyLogger.i(TAG,"从网络上加载了图片");
        //执行磁盘缓存
        LocalCacheUtils.saveCache(context,bitmap,url);
        //把数据缓存在内存中
        MemoryCacheUtils.saveCache(bitmap,url);
        return bitmap;
    }
内存缓存
写入内存

从内存读

修改图片加载工具类
[Java] 纯文本查看 复制代码
public class BitmapUtils {


    private static final String TAG = "BitmapUtils";

    static{
        netCacheUtils = new NetCacheUtils();
        localCacheUtils = new LocalCacheUtils();
        memoryCacheUtils = new MemoryCacheUtils();
    }

    private static NetCacheUtils netCacheUtils;
    private static LocalCacheUtils localCacheUtils;
    private static MemoryCacheUtils memoryCacheUtils;

    //显示图片
    public static void display(Context context,ImageView iv, String url){
        Bitmap bitmap = null;
        //内存缓存
        bitmap = memoryCacheUtils.readCache(url);
        if(bitmap != null){
            iv.setImageBitmap(bitmap);
            MyLogger.i(TAG,"从内存获取了图片");
            return;
        }
        //磁盘缓存
        bitmap = localCacheUtils.readCache(context, url);
        if(bitmap != null){
            iv.setImageBitmap(bitmap);
            MyLogger.i(TAG,"从磁盘获取了图片");
            return;
        }
        //网络缓存
        netCacheUtils.getBitmapFromNet(context,iv,url);
    }
}






作者: k1453711238    时间: 2017-8-2 23:04
多谢大哥分享啊,希望持续更新啊
作者: baby14    时间: 2018-12-29 08:31
多谢分享




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2