zoukankan      html  css  js  c++  java
  • Android之ListView异步加载图片且仅显示可见子项中的图片

    折腾了好多天,遇到 N 多让人崩溃无语的问题,不过今天终于有些收获了,这是实验的第一版,有些混乱,下一步进行改造细分,先把代码记录在这儿吧。

    网上查了很多资料,发现都千篇一律,抄来抄去,很多细节和完整实例都没看到,只有自己一点点研究了,总体感觉 android 下面要显示个图片真不容易啊。


    项目主要实现的功能:

    异步加载图片图片内存缓存、异步磁盘文件缓存解决使用 viewHolder 后出现的图片错位问题优化列表滚动性能,仅显示可见子项中的图片无需固定图片显示高度,对高度进行缓存使列表滚动时不会因图片高度变化而闪动,使滚动体验 更加流畅图片动画展示效果,新加载的图片显示透明渐变动画

    没有涉及到下拉加载和刷新数据,目前还没接触到这些,而且已发现自定义 ListView 中如果有添加 顶部和底部 的拉动加载更多数据提示的 view ,将会导致 ListView 的 child 数量和 position 混乱,所以只有先简单使用 ListView 来做个效果。


    核心主要是三个文件:MainActivity.java, ZAsyncImageLoader.java, DiaryListAdapter.java

    下面贴代码:


    MainActivity.java

    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    package com.ai9475.meitian;
     
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.charset.Charset;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Iterator;
     
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.drawable.Drawable;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.Handler;
    import android.os.Looper;
    import android.support.v4.app.FragmentTransaction;
    import android.support.v7.app.ActionBar;
    import android.support.v7.app.ActionBarActivity;
    import android.util.JsonReader;
    import android.util.Log;
    import android.view.Menu;
    import android.view.View;
    import android.widget.AbsListView;
    import android.widget.AdapterView;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.SimpleAdapter;
    import android.widget.TextView;
    import android.widget.Toast;
     
    import com.ai9475.meitian.adapter.DiaryListAdapter;
    import com.ai9475.util.ZAsyncImageLoader;
    import com.ai9475.util.ZHttpRequest;
    import com.ai9475.util.ZLog;
    import com.ai9475.widget.PullToRefreshListView;
     
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.mime.MultipartEntityBuilder;
    import org.apache.http.protocol.HTTP;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    import org.json.JSONStringer;
    import org.w3c.dom.Text;
     
    public class MainActivity extends ActionBarActivity
    {
        private static final String TAG = "MainActivity";
     
        private ListView mDiaryListView;
     
        private DiaryListAdapter mDiaryListAdapter;
     
        private ZAsyncImageLoader mAsyncImageLoader;
     
        private Handler handler = new Handler();
     
        private int endId = 0;
     
        private boolean isScrolling = false;
     
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            Log.d("main activity", "start");
            // 执行父级初始化方法
            super.onCreate(savedInstanceState);
            // 让 ActionBar 浮动在 Activity 上方进行半透明遮盖
            //this.supportRequestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
            // 解析视图数据
            this.setContentView(R.layout.activity_main);
            AppManager.getInstance().addActivity(this);
     
            this.mAsyncImageLoader = new ZAsyncImageLoader();
            this.mAsyncImageLoader.setIsUseDiskCache(true);
            this.mAsyncImageLoader.setCacheDir(AppConfig.IMAGE_CACHE_PATH);
     
            // 配置 ActionBar 相关
            final ActionBar bar = this.getSupportActionBar();
            // 标题
            bar.setTitle("Bar");
            // 返回按钮
            //bar.setDisplayHomeAsUpEnabled(true);
            // 应用徽标控制
            //bar.setDisplayUseLogoEnabled(false);
            // 应用图标控制
            //bar.setDisplayShowHomeEnabled(true);
            // 标题栏控制
            //bar.setDisplayShowTitleEnabled(true);
            // 设置 TABS 导航模式
            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            /*
            bar.getHeight();
            final ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
            ViewTreeObserver scvto = scrollView.getViewTreeObserver();
            if (scvto != null) {
                scvto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {
                        scrollView.setPadding(
                                scrollView.getPaddingLeft(),
                                bar.getHeight(),
                                scrollView.getPaddingRight(),
                                scrollView.getPaddingBottom()
                        );
                        return true;
                    }
                });
            }*/
            /*Fragment fragmentA = new FragmentTab();
            Fragment fragmentB = new FragmentTab();
            Fragment fragmentC = new FragmentTab();
     
            tabA.setTabListener(new MyTabsListener(fragmentA));
            tabB.setTabListener(new MyTabsListener(fragmentB));
            tabC.setTabListener(new MyTabsListener(fragmentC));*/
     
            bar.addTab(bar.newTab().setText("ATab").setTabListener(new MyTabsListener()));
            bar.addTab(bar.newTab().setText("BTab").setTabListener(new MyTabsListener()));
            bar.addTab(bar.newTab().setText("CTab").setTabListener(new MyTabsListener()));
     
            /*//bar.setDisplayShowHomeEnabled(false);
            //bar.setDisplayShowTitleEnabled(false);
            // 顶部帧布局操作栏
            final FrameLayout topActBar = (FrameLayout) findViewById(R.id.topActionBar);
            // 底部帧布局操作栏
            final FrameLayout bottomActBar = (FrameLayout) findViewById(R.id.bottomActionBar);
            // 列表滚动视图
            final ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView);
            // 顶部操作栏绑定事件:同步设置滚动视图顶部内边距
            topActBar
                    .getViewTreeObserver()
                    .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                        @Override
                        public boolean onPreDraw() {
                            scrollView.setPadding(
                                    scrollView.getPaddingLeft(),
                                    topActBar.getHeight(),
                                    scrollView.getPaddingRight(),
                                    scrollView.getPaddingBottom()
                            );
                            return true;
                        }
                    });
            // 底部操作栏绑定事件:同步设置滚动视图底部内边距
            bottomActBar
                    .getViewTreeObserver()
                    .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                        @Override
                        public boolean onPreDraw() {
                            scrollView.setPadding(
                                    scrollView.getPaddingLeft(),
                                    scrollView.getPaddingTop(),
                                    scrollView.getPaddingRight(),
                                    bottomActBar.getHeight()
                            );
                            return true;
                        }
                    });
     
            */
     
            //AppContext context = (AppContext) getApplicationContext();
            //context.test();
    /*
            ZAsyncImageLoader loader = new ZAsyncImageLoader();
            loader.loadDrawable(url1, new ZAsyncImageLoader.OnImageLoadListener() {
                @Override
                public void onLoaded(Drawable imageDrawable, String imageUrl) {
                    ImageView img = (ImageView) findViewById(R.id.showPic1);
                    img.setImageDrawable(imageDrawable);
                }
            });
            loader.loadDrawable(url2, new ZAsyncImageLoader.OnImageLoadListener() {
                @Override
                public void onLoaded(Drawable imageDrawable, String imageUrl) {
                    ImageView img = (ImageView) findViewById(R.id.showPic2);
                    img.setImageDrawable(imageDrawable);
                }
            });*/
            // 找到日记列表视图对象
            this.mDiaryListView = (ListView) findViewById(R.id.diaryListCt);
            new Thread(){
                @Override
                public void run() {
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            loadDiaryListData();
                        }
                    };
                    handler.post(runnable);
                }
            }.start();
        }
     
        /**
         * 日记列表初始化
         */
        protected void initDiaryList(JSONArray diaryList)
        {
            Log.d("initDiaryList", "start");
            // 列表单元与数据的适配器生成
            this.mDiaryListAdapter = new DiaryListAdapter(this, this.mDiaryListView, this.mAsyncImageLoader, diaryList);
            // 绑定列表数据单元适配器
            Log.d("initDiaryList", "setAdapter");
            this.mDiaryListView.setAdapter(this.mDiaryListAdapter);
            Log.d("bindListViewEvents", "start");
            // 绑定日记列表事件
            this.bindListViewEvents();
            Log.d("DiaryListAdapter", "end");
        }
     
        static int j = 0;
        /**
         * 绑定日记列表事件
         */
        public void bindListViewEvents()
        {
            // 列表滚动事件
            this.mDiaryListView.setOnScrollListener(new AbsListView.OnScrollListener(){
                @Override
                public void onScrollStateChanged(AbsListView absListView, int scrollState)
                {
                    switch (scrollState) {
                        case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                            ZLog.i(TAG, "OnScrollListener : SCROLL_STATE_TOUCH_SCROLL");
                            mDiaryListAdapter.setIsSCrolling(true);
                            break;
                        case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
                            ZLog.i(TAG, "OnScrollListener : SCROLL_STATE_FLING");
                            mDiaryListAdapter.setIsSCrolling(true);
                            break;
                        case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                            // 第一个可见 item 的 position
                            int first = mDiaryListView.getFirstVisiblePosition();
                            // 最后一个可见 item 的 position
                            int last = mDiaryListView.getLastVisiblePosition();
                            // 屏幕上可见 item 的总数
                            int onScreenCount = mDiaryListView.getChildCount();
                            int total = first + last;
                            ZLog.i(TAG, "OnScrollListener : SCROLL_STATE_IDLE => " + (j++) +", first: "+ first +", last: "+ last +", total: "+ total +", onScreenCount:"+ onScreenCount);
                            mDiaryListAdapter.setIsSCrolling(false);
                            mDiaryListAdapter.setPositionRange(first, last);
                            View child;
                            int position;
                            for (int i = 0; i < onScreenCount; i++) {
                                position = first + i;
                                if (mDiaryListAdapter.isInPrevPositionRange(position)) {
                                    ZLog.i(TAG, "inPrevPositionRange position:"+ position);
                                    continue;
                                }
                                // 获取可见 item 子项的视图容器对象
                                child = mDiaryListView.getChildAt(i);
                                ImageView picPhoto = (ImageView) child.findViewById(R.id.picPhoto);
                                ImageView avatar = (ImageView) child.findViewById(R.id.avatar);
                                try {
                                    ZLog.i(TAG, "load image i:"+ first);
                                    mDiaryListAdapter.loadImage(picPhoto, avatar, mDiaryListAdapter.getItem(position));
                                } catch (JSONException e) {
                                    AppException.io(e);
                                }
                            }
                            break;
                        default:
                            break;
                    }
                }
     
                @Override
                public void onScroll(AbsListView absListView, int first, int last, int total) {
                    //mDiaryListAdapter.setPositionLimit(first, last);
                    //ZLog.i(TAG, "OnScrollListener : onScroll => " + (j++) +", first: "+ first +", last: "+ last +", total:"+ total);
                }
            });
     
            // 列表单元点击事件
            ZLog.i(TAG, "diaryListInit : setOnItemClickListener");
            this.mDiaryListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<!--?--> adapterView, View view, int i, long l) {
                    getSupportActionBar().setTitle("点击了: "+ i);
                }
            });
     
            ZLog.i("DiaryListAdapter", "setOnRefreshListener");
            // 当向下拉动刷新时触发列表更新事件
            /*this.mDiaryListView.setOnRefreshListener(new PullToRefreshListView.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    getSupportActionBar().setTitle("执行加载…");
                    loadDiaryListData();
                    mDiaryListView.onRefreshComplete();
                }
            });*/
        }
     
        public void loadDiaryListData()
        {
            ZLog.i(TAG, "loadDiaryListData : start");
            try {
                ZHttpRequest httpRequset = new ZHttpRequest(new ZHttpRequest.OnHttpRequestListener() {
                    @Override
                    public void onRequest(ZHttpRequest request) {
                        ZLog.i(TAG, "request data : start");
                    }
     
                    @Override
                    public void onSucceed(int statusCode, ZHttpRequest request) {
                        // 创建每行数据的集合
                        ZLog.i(TAG, "request onSucceed : start");
                        try {
                            String content = request.getInputStream();
                            if (content == null) {
                                Toast.makeText(getApplicationContext(), "数据请求失败", Toast.LENGTH_SHORT).show();
                                return;
                            }
                            JSONArray diaryList = new JSONArray(content);
                            /*if (asyncImageLoader.getMaxPosition() < 1) {
                                asyncImageLoader.setPositionLimit(0, diaryList.length());
                            }*/
                            endId = ((JSONObject) diaryList.opt(diaryList.length() - 1)).getInt("id");
                            initDiaryList(diaryList);
                        } catch (IOException e) {
                            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
                        } catch (JSONException e) {
                            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
                        }
     
                    }
     
                    @Override
                    public void onFailed(int statusCode, ZHttpRequest request) {
                        ZLog.i(TAG, "request onFailed : code"+ statusCode);
                    }
                });
                httpRequset.get("http://m.ai9475.com/?con=meitian_app&endId=" + this.endId);
            } catch (Exception e) {
                e.printStackTrace();
                Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
            }
        }
     
        protected class MyTabsListener implements ActionBar.TabListener
        {
    //        private Fragment fragment;
     
    //        public MyTabsListener(Fragment fragment)
    //        {
    //            this.fragment = fragment;
    //        }
     
            @Override
            public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft)
            {
    //            ft.add(R.id.fragmentPlace, this.fragment, null);
            }
     
            @Override
            public void onTabReselected(ActionBar.Tab arg0, FragmentTransaction arg1) {
                // TODO Auto-generated method stub
     
            }
     
            @Override
            public void onTabUnselected(ActionBar.Tab arg0, FragmentTransaction arg1) {
                // TODO Auto-generated method stub
     
            }
        }
     
        /**
         * 配置 ActionBar
         *
         * @param menu
         * @return
         */
        public boolean onCreateOptionsMenu(Menu menu)
        {
            this.getMenuInflater().inflate(R.menu.main, menu);
            return super.onCreateOptionsMenu(menu);
        }
     
        /*public void doClick(View view)
        {
            ZHttpRequest get = new ZHttpRequest();
            get
                    .setCharset(HTTP.UTF_8)
                    .setConnectionTimeout(5000)
                    .setSoTimeout(5000);
            get.setOnHttpRequestListener(new ZHttpRequest.OnHttpRequestListener() {
                @Override
                public void onRequest(ZHttpRequest request) throws Exception {
     
                }
     
                @Override
                public String onSucceed(int statusCode, ZHttpRequest request) throws Exception {
                    return request.getInputStream();
                }
     
                @Override
                public String onFailed(int statusCode, ZHttpRequest request) throws Exception {
                    return "GET 请求失败:statusCode "+ statusCode;
                }
            });
     
            ZHttpRequest post = new ZHttpRequest();
            post
                    .setCharset(HTTP.UTF_8)
                    .setConnectionTimeout(5000)
                    .setSoTimeout(10000);
            post.setOnHttpRequestListener(new ZHttpRequest.OnHttpRequestListener() {
                private String CHARSET = HTTP.UTF_8;
                private ContentType TEXT_PLAIN = ContentType.create("text/plain", Charset.forName(CHARSET));
     
                @Override
                public void onRequest(ZHttpRequest request) throws Exception {
                    // 设置发送请求的 header 信息
                    request.addHeader("cookie", "abc=123;456=爱就是幸福;");
                    // 配置要 POST 的数据
                    MultipartEntityBuilder builder = request.getMultipartEntityBuilder();
                    builder.addTextBody("p1", "abc");
                    builder.addTextBody("p2", "中文", TEXT_PLAIN);
                    builder.addTextBody("p3", "abc中文cba", TEXT_PLAIN);
                    if (picPath != null && ! "".equals(picPath)) {
                        builder.addTextBody("pic", picPath);
                        builder.addBinaryBody("file", new File(picPath));
                    }
                    request.buildPostEntity();
                }
     
                @Override
                public String onSucceed(int statusCode, ZHttpRequest request) throws Exception {
                    return request.getInputStream();
                }
     
                @Override
                public String onFailed(int statusCode, ZHttpRequest request) throws Exception {
                    return "POST 请求失败:statusCode "+ statusCode;
                }
            });
     
            TextView textView = (TextView) findViewById(R.id.showContent);
            String content = "初始内容";
            try {
                if (view.getId() == R.id.doGet) {
                    content = get.get("http://www.baidu.com");
                    content = "GET数据:isGet: " + (get.isGet() ? "yes" : "no") + " =>" + content;
                } else {
                    content = post.post("http://192.168.1.6/test.php");
                    content = "POST数据:isPost" + (post.isPost() ? "yes" : "no") + " =>" + content;
                }
     
            } catch (IOException e) {
                content = "IO异常:" + e.getMessage();
            } catch (Exception e) {
                content = "异常:" + e.getMessage();
            }
            textView.setText(content);
        }
     
        public void doPhoto(View view)
        {
            destoryBimap();
            String state = Environment.getExternalStorageState();
            if (state.equals(Environment.MEDIA_MOUNTED)) {
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                startActivityForResult(intent, 1);
            } else {
                Toast.makeText(MainActivity.this, "没有SD卡", Toast.LENGTH_LONG).show();
            }
        }
     
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data)
        {
            Uri uri = data.getData();
            if (uri != null) {
                this.photo = BitmapFactory.decodeFile(uri.getPath());
            }
            if (this.photo == null) {
                Bundle bundle = data.getExtras();
                if (bundle != null) {
                    this.photo = (Bitmap) bundle.get("data");
                } else {
                    Toast.makeText(MainActivity.this, "拍照失败", Toast.LENGTH_LONG).show();
                    return;
                }
            }
     
            FileOutputStream fileOutputStream = null;
            try {
                // 获取 SD 卡根目录
                String saveDir = Environment.getExternalStorageDirectory() + "/meitian_photos";
                // 新建目录
                File dir = new File(saveDir);
                if (! dir.exists()) dir.mkdir();
                // 生成文件名
                SimpleDateFormat t = new SimpleDateFormat("yyyyMMddssSSS");
                String filename = "MT" + (t.format(new Date())) + ".jpg";
                // 新建文件
                File file = new File(saveDir, filename);
                // 打开文件输出流
                fileOutputStream = new FileOutputStream(file);
                // 生成图片文件
                this.photo.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
                // 相片的完整路径
                this.picPath = file.getPath();
                ImageView imageView = (ImageView) findViewById(R.id.showPhoto);
                imageView.setImageBitmap(this.photo);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (fileOutputStream != null) {
                    try {
                        fileOutputStream.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
     
        /**
         * 销毁图片文件
         *
        private void destoryBimap()
        {
            if (photo != null && ! photo.isRecycled()) {
                photo.recycle();
                photo = null;
            }
        }*/
    }


    其中涉及到 scroll 滚动相关的事件,我一开始在这里折腾了好久,可以去看看我这篇文章:

    Android 关于 OnScrollListener 事件顺序次数的简要分析



    ZAsyncImageLoader.java

    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    package com.ai9475.util;
     
    import android.graphics.drawable.Drawable;
    import android.os.Handler;
    import android.os.Message;
     
    import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.lang.ref.SoftReference;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
     
    /**
     * 异步多线程加载图片
     *
     * Created by ZHOUZ on 14-2-7.
     */
    public class ZAsyncImageLoader
    {
        private static final String TAG = "ZAsyncImageLoader";
     
        /**
         * 线程池中的线程数量
         */
        private int mThreadSize = 5;
     
        /**
         * 是否使用 SD 卡缓存图片
         */
        private boolean mIsUseDiskCache = false;
     
        /**
         * SD 卡上缓存的图片有效期(单位:秒)
         */
        private int mExpireTime = 86400;
     
        /**
         * 图片缓存文件目录
         */
        private String mCachePath = null;
     
        /**
         * 同步缓存已加载过的图片,使用软引用优化内存
         */
        private HashMap<string, softreference<drawable="">> mImageCaches = new HashMap<string, softreference<drawable="">>();
     
        /**
         * 使用线程池,根据 CPU 数量来动态决定可用线程数量
         */
        private ExecutorService mExecutorService = null;
     
        /**
         * 设置 SD 卡中的图片缓存有效时长(单位:秒)
         *
         * @param time
         */
        public void setExpireTime(int time) {
            this.mExpireTime = time;
        }
     
        /**
         * 设置线程数量
         *
         * @param size
         */
        public void setThreadSize(int size) {
            this.mThreadSize = size;
        }
     
        /**
         * 设置是否使用 SD 卡缓存图片
         *
         * @param isUse
         */
        public void setIsUseDiskCache(Boolean isUse) {
            this.mIsUseDiskCache = isUse;
        }
     
        /**
         * 设置缓存目录
         *
         * @param path
         */
        public void setCacheDir(String path) {
            this.mCachePath = path;
        }
     
        /**
         * 获取线程池管理器
         *
         * @return
         */
        public ExecutorService getExecutorService() {
            if (this.mExecutorService == null) {
                if (this.mThreadSize < 1) {
                    this.mThreadSize = Runtime.getRuntime().availableProcessors() * 5;
                }
                this.mExecutorService = Executors.newFixedThreadPool(this.mThreadSize);
            }
            return this.mExecutorService;
        }
     
        /**
         * 加载图片的多线程控制
         *
         * @param imageUrl
         * @param tag
         * @param listener
         */
        public Drawable loadDrawable(final String imageUrl, final String tag, final OnImageLoadListener listener)
        {
            // 是否已缓存过图片, 是则从缓存中直接获取, 若缓存中数据丢失则重新远程加载
            if (this.mImageCaches.containsKey(imageUrl)) {
                SoftReference<drawable> softReference = this.mImageCaches.get(imageUrl);
                if (softReference != null) {
                    Drawable drawable = softReference.get();
                    if (drawable != null) {
                        return drawable;
                    }
                }
            }
     
            // 异步多线程加载图片后的数据传递处理
            final Handler handler = new Handler() {
                @Override
                public void handleMessage(Message message) {
                    if (message.what == 1) {
                        listener.onLoaded((Drawable) message.obj, imageUrl, tag);
                    } else {
                        listener.onFailed((IOException) message.obj, imageUrl, tag);
                    }
                }
            };
     
            // 通过线程池来控制管理图片加载
            this.getExecutorService().submit(new Runnable() {
                @Override
                public void run() {
                    Message msg;
                    try {
                        Drawable drawable = loadImageFromUrl(imageUrl);
                        mImageCaches.put(imageUrl, new SoftReference<drawable>(drawable));
                        msg = handler.obtainMessage(1, drawable);
                    } catch (IOException e) {
                        msg = handler.obtainMessage(0, e);
                    }
                    handler.sendMessage(msg);
                }
            });
     
            return null;
        }
     
        /**
         * 加载远程图片或本地图片缓存文件
         *
         * @param imageUrl
         * @return
         * @throws IOException
         */
        public Drawable loadImageFromUrl(String imageUrl) throws IOException
        {
            // 检查 SD 卡是否可用并将图片缓存到 SD 卡上
            if (mIsUseDiskCache && mCachePath != null)
            {
                File d = new File(mCachePath);
                if (! d.exists()) {
                    d.mkdirs();
                }
     
                final File f = new File(mCachePath + ZHelper.md5(imageUrl));
                long time = (new Date()).getTime();
                long expire = time - (mExpireTime * 1000L);
     
                // 文件存在且在有效期内则直接读取
                if (f.exists() && f.lastModified() > expire) {
                    FileInputStream fis = new FileInputStream(f);
                    return Drawable.createFromStream(fis, "src");
                }
     
                // 远程加载图片后写入到 SD 卡上
                InputStream i = this.getImageInputStream(imageUrl);
                if (i == null) {
                    return null;
                }
     
                final Drawable drawable = Drawable.createFromStream(i, "src");
     
                // 将图片异步写入到本地 SD 卡中缓存, 避免阻塞UI线程, 导致图片不能显示
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            InputStream i = ZFormat.drawable2InputStream(drawable);
                            DataInputStream in = new DataInputStream(i);
                            FileOutputStream out = new FileOutputStream(f);
                            byte[] buffer = new byte[1024];
                            int byteRead;
                            while ((byteRead = in.read(buffer)) != -1) {
                                out.write(buffer, 0, byteRead);
                            }
                            in.close();
                            out.close();
                        } catch (IOException e) {
                            ZLog.d("write image cache IOException", e.getMessage());
                            e.printStackTrace();
                        }
                    }
                }).start();
     
                return drawable;
            }
            // 只读取远程图片不缓存
            else {
                InputStream i = this.getImageInputStream(imageUrl);
                return Drawable.createFromStream(i, "src");
            }
        }
     
        /**
         * 远程加载图片数据
         *
         * @param imageUrl
         * @return
         * @throws IOException
         */
        public InputStream getImageInputStream(String imageUrl) throws IOException
        {
            URL m = new URL(imageUrl);
            HttpURLConnection conn = (HttpURLConnection) m.openConnection();
            conn.setRequestMethod("GET");
            conn.setUseCaches(false);
            conn.setDoInput(true);
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setInstanceFollowRedirects(true);
            return conn.getInputStream();
        }
     
        /**
         * 加载图片的事件监听器
         */
        public interface OnImageLoadListener {
            /**
             * 图片加载完成事件处理
             *
             * @param imageDrawable
             * @param imageUrl
             * @param tag
             */
            public void onLoaded(Drawable imageDrawable, String imageUrl, String tag);
     
            /**
             * 图片加载失败的事件处理
             *
             * @param e
             * @param imageUrl
             * @param tag
             */
            public void onFailed(IOException e, String imageUrl, String tag);
        }
     
        protected void finalize()
        {
            this.mExecutorService.shutdown();
        }
    }
    </drawable></drawable></string,></string,>



    DiaryListAdapter.java

    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    package com.ai9475.meitian.adapter;
     
    import android.content.Context;
    import android.graphics.drawable.Drawable;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.AlphaAnimation;
    import android.widget.AbsListView;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    import android.widget.Toast;
     
    import com.ai9475.meitian.R;
    import com.ai9475.util.ZAsyncImageLoader;
    import com.ai9475.util.ZHelper;
    import com.ai9475.util.ZLog;
    import com.ai9475.util.ZUI;
     
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
     
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;
     
    /**
     * Created by ZHOUZ on 14-2-8.
     */
    public class DiaryListAdapter extends BaseAdapter implements AbsListView.RecyclerListener
    {
        private static final String TAG = "DiaryListAdapter";
     
        private Context mContext;
        private ListView mDiaryListView;
        public View mConvertView;
        private ZAsyncImageLoader mAsyncImageLoader;
        private JSONArray mDiaryDataList = null;
        private boolean mIsScrolling = false;
        private int mFirstPosition = 0;
        private int mLastPosition = 0;
        private int mPrevFirstPosition = 0;
        private int mPrevLastPosition = 0;
        private HashMap<string, integer=""> mImagesHeight = new HashMap<string, integer="">();
     
        public DiaryListAdapter(Context context, ListView listView, ZAsyncImageLoader imageLoader, JSONArray diaryList)
        {
            this.mContext = context;
            this.mAsyncImageLoader = imageLoader;
            this.mDiaryDataList = diaryList;
            this.mDiaryListView = listView;
        }
     
        public void setIsSCrolling(boolean flag)
        {
            this.mIsScrolling = flag;
        }
     
        /**
         * 当前列表加载到的日记总数
         *
         * @return
         */
        public int getCount() {
            return this.mDiaryDataList == null ? 0 : this.mDiaryDataList.length();
        }
     
        /**
         * 可见单元位置对比是否处在在上次滚动可是范围内
         *
         * @param position
         * @return
         */
        public boolean isInPrevPositionRange(int position) {
            // 初始化时直接返回 false
            if (this.mPrevLastPosition == 0) return false;
            // 检测当前 item 的位置是否在上次滚动范围内, 是则表示该 item 正处于屏幕可见状态中无需重新加载
            return (position >= this.mPrevFirstPosition && position <= this.mPrevLastPosition) ? true : false;
        }
     
        /**
         * 设置滚动后可见的起止项目序号
         *
         * @param first
         * @param last
         */
        public void setPositionRange(int first, int last) {
            // 保存上次滚动后的可见位置
            this.mPrevFirstPosition = this.mFirstPosition;
            this.mPrevLastPosition = this.mLastPosition;
            // 重置当前可见位置
            this.mFirstPosition = first;
            this.mLastPosition = last;
            ZLog.i(TAG, "setPositionLimit prevFirst: "+ mPrevFirstPosition +", prevLast: "+ mPrevLastPosition +", first: "+ mFirstPosition +", last: "+ mLastPosition);
        }
     
        /**
         * 获取当前列表单元的日记id
         *
         * @param position
         * @return
        */
        public long getItemId(int position) {
            int id = 0;
            try {
                id = this.getItem(position).getInt("id");
            } catch (JSONException e) {
                Toast.makeText(this.mContext, e.getMessage(), Toast.LENGTH_LONG);
            }
            return id;
        }
     
        /**
         * 获取一条数据
         *
         * @param position
         * @return
         */
        public JSONObject getItem(int position) {
            return (JSONObject) this.mDiaryDataList.opt(position);
        }
     
        /**
         * 获取视图
         *
         * @param position
         * @param convertView
         * @param parent
         * @return
         */
        public View getView(int position, View convertView, ViewGroup parent)
        {
            ZLog.v(TAG, "getView i: " + position);
     
            final ViewHolder holder;
            if (convertView == null) {
                convertView = LayoutInflater.from(this.mContext).inflate(R.layout.list_item_diary, null);
                this.mConvertView = convertView;
                holder = new ViewHolder(convertView);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
     
            try {
                // 获取当前列表单元的 JSON 日记数据
                JSONObject item = this.getItem(position);
                ZLog.i(TAG, "getView i: "+ position +", isScrolling: "+ mIsScrolling +", mFirstPosition: "+ mFirstPosition +", mLastPosition: "+ mLastPosition);
     
                /*if (! isScrolling && (position >= mFirstPosition && position <= mLastPosition)) {
                    ZLog.i(TAG, "getView i: "+ position +", show images");
                    this.loadImage(holder.picPhoto, holder.avatar, item);
                } else {*/
                    ZLog.i(TAG, "getView i: "+ position +", can't show images");
                // 初始化时自动加载
                if (this.mLastPosition == 0) {
                    this.loadImage(holder.picPhoto, holder.avatar, item);
                    this.mPrevLastPosition = position;
                } else {
                    this.setDefaultImage(holder.picPhoto, holder.avatar, item);
                }
     
                    /*holder.picPhoto.setScaleType(ImageView.ScaleType.CENTER);
                    holder.picPhoto.setImageResource(R.drawable.default_pic);
                    holder.avatar.setScaleType(ImageView.ScaleType.CENTER);
                    holder.avatar.setImageResource(R.drawable.default_avatar);
                }*/
                holder.nickname.setText(item.getString("nickname") +":"+ position);
                holder.content.setText(item.getString("content"));
                holder.calendarMonth.setText(ZHelper.dateFormat("MM月", item.getInt("calendarDate")));
                holder.calendarDay.setText(ZHelper.dateFormat("dd", item.getInt("calendarDate")));
            } catch (JSONException e) {
                Toast.makeText(this.mContext, e.getMessage(), Toast.LENGTH_LONG);
            }
     
            return convertView;
        }
     
        public void setDefaultImage(ImageView picPhoto, ImageView avatar, JSONObject item) throws JSONException
        {
            int height = 0;
            String picUrl = getPicUrl(item.getString("picUrl"));
            if (mImagesHeight.containsKey(picUrl)) {
                height = mImagesHeight.get(picUrl);
            }
     
            int minHeight = ZUI.dp2px(this.mContext, 100);
            if (height < minHeight) height = minHeight;
     
            picPhoto.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
            picPhoto.setScaleType(ImageView.ScaleType.CENTER);
            picPhoto.setImageResource(R.drawable.default_pic);
            avatar.setScaleType(ImageView.ScaleType.CENTER);
            avatar.setImageResource(R.drawable.default_avatar);
        }
     
        public String getPicUrl(String pic)
        {
        }
     
        public String getAvatarUrl(String avatar)
        {
            return "http://img.ai9475.com/data/attachment/images/avatar/" + avatar;
        }
     
        /**
         * 加载可见单元的图片
         *
         * @param picPhoto
         * @param avatar
         * @param item
         * @throws JSONException
         */
        public void loadImage(ImageView picPhoto, ImageView avatar, JSONObject item) throws JSONException
        {
            // 图片链接
            String picUrl = getPicUrl(item.getString("picUrl"));
            String avatarUrl = getAvatarUrl(item.getString("avatar"));
     
            // 记录异步加载的图片标签
            String picTag = "pic"+ item.getInt("calendarDate") + item.getInt("id");
            String avatarTag = "avatar"+ item.getInt("id");
     
            picPhoto.setTag(picTag);
            avatar.setTag(avatarTag);
     
            OnPicLoadListener mOnPicLoadListener = new OnPicLoadListener();
            OnAvatarLoadListener mOnAvatarLoadListener = new OnAvatarLoadListener();
     
            // 异步加载远程日记照片或缓存
            Drawable picDrawable = this.mAsyncImageLoader.loadDrawable(picUrl, picTag, mOnPicLoadListener);
            // 存在缓存则使用缓存中的图片资源或者使用默认占位图
            mOnPicLoadListener.setDrawable(picPhoto, picUrl, picTag, picDrawable);
     
            // 异步加载远程用户头像或加载缓存
            Drawable avatarDrawable = this.mAsyncImageLoader.loadDrawable(avatarUrl, avatarTag, mOnAvatarLoadListener);
            // 存在缓存则使用缓存中的图片资源或者使用默认占位图
            mOnAvatarLoadListener.setDrawable(avatar, avatarUrl, avatarTag, avatarDrawable);
        }
     
        /**
         * 当列表单元滚动到可是区域外时清除掉已记录的图片视图
         *
         * @param view
         */
        @Override
        public void onMovedToScrapHeap(View view) {
            /*ViewHolder holder = (ViewHolder) view.getTag();
            this.imageViews.remove(holder.avatar);
            this.imageViews.remove(holder.picPhoto);*/
        }
     
        private static class ViewHolder
        {
            public ImageView picPhoto;
            public ImageView avatar;
            public TextView nickname;
            public TextView content;
            public TextView calendarMonth;
            public TextView calendarDay;
     
            public ViewHolder(View view)
            {
                this.picPhoto = (ImageView) view.findViewById(R.id.picPhoto);
                this.avatar = (ImageView) view.findViewById(R.id.avatar);
                this.nickname = (TextView) view.findViewById(R.id.nickname);
                this.content = (TextView) view.findViewById(R.id.content);
                this.calendarMonth = (TextView) view.findViewById(R.id.calendarMonth);
                this.calendarDay = (TextView) view.findViewById(R.id.calendarDay);
            }
        }
     
        /**
         * 头像图片加载事件监听
         */
        private class OnAvatarLoadListener extends OnImageLoadListener
        {
            private int mImageSource = R.drawable.default_avatar;
     
            /**
             * 设置图片
             *
             * @param view
             * @param imageUrl
             * @param tag
             * @param drawable
             */
            public void setDrawable(ImageView view, String imageUrl, String tag, Drawable drawable)
            {
                if (view == null) return;
                if (drawable != null) {
                    view.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    view.setImageDrawable(drawable);
                } else {
                    view.setScaleType(ImageView.ScaleType.CENTER);
                    view.setImageResource(this.mImageSource);
                }
            }
        }
     
        /**
         * 日记照片加载事件监听
         */
        private class OnPicLoadListener extends OnImageLoadListener
        {
            private int mImageSource = R.drawable.default_pic;
     
            /**
             * 设置图片
             *
             * @param view
             * @param imageUrl
             * @param tag
             * @param drawable
             */
            public void setDrawable(ImageView view, String imageUrl, String tag, Drawable drawable)
            {
                if (view == null) return;
                int height = 0;
                if (mImagesHeight.containsKey(imageUrl)) {
                    height = mImagesHeight.get(imageUrl);
                }
                if (drawable != null) {
                    // 定义图片的最佳高度
                    if (height == 0) {
                        int minHeight = ZUI.dp2px(mContext, 100);
                        int maxHeight = ZUI.dp2px(mContext, 300);
                        height = (int) ((float) view.getWidth() / drawable.getMinimumWidth() * drawable.getMinimumHeight());
                        if (height > maxHeight) {
                            height = maxHeight;
                        } else if (height < minHeight) {
                            height = minHeight;
                        }
                        mImagesHeight.put(imageUrl, height);
                    }
                    // 现将图片完全透明
                    drawable.setAlpha(0);
                    view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
                    view.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    view.setImageDrawable(drawable);
                    // 添加透明渐变动画显示图片
                    AlphaAnimation alphaAnim = new AlphaAnimation(0.0f, 1.0f);
                    alphaAnim.setDuration(1000);
                    view.setAnimation(alphaAnim);
                } else {
                    int minHeight = ZUI.dp2px(mContext, 100);
                    height = height < minHeight ? minHeight : height;
                    view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
                    view.setScaleType(ImageView.ScaleType.CENTER);
                    view.setImageResource(mImageSource);
                }
            }
        }
     
        /**
         * 图片的加载监听事件
         */
        abstract private class OnImageLoadListener implements ZAsyncImageLoader.OnImageLoadListener
        {
            /**
             * 实现图片显示的抽象方法
             *
             * @param view
             * @param tag
             * @param drawable
             */
            abstract public void setDrawable(ImageView view, String imageUrl, String tag, Drawable drawable);
     
            @Override
            public void onLoaded(Drawable drawable, String imageUrl, String tag) {
                ImageView view = (ImageView) mDiaryListView.findViewWithTag(tag == null ? imageUrl : tag);
                this.setDrawable(view, imageUrl, tag, drawable);
            }
     
            @Override
            public void onFailed(IOException e, String imageUrl, String tag) {
                //Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
            }
        }
    }</string,></string,>


    代码相关的一些类方法,以及涉及到的其他方面问题的相关博文:

    android 一些数据转换方法

    Android实现图片宽度100%ImageView宽度且高度按比例自动伸缩


    n块ズ��椐鷌�源码:http://yunpan.cn/QpzhBEWCw3gDH

    项目中需要修改服务端的地址,我在压缩包中附有一些 服务端发送的 JSON 数据


    还可以加入 Android 文件共享群,这里全是 Android 和 JAVA 学习资料和教程:http://qun.yunpan.360.cn/38063538

  • 相关阅读:
    非常奇怪的VS2005无法调试的问题
    自已写的“动易PowerEasy2006暴库工具”
    用VBA去除Excel工作表保护密码
    mapgis同arcmap之间的数据转换, 投影变换,误差校正,坐标,基础资料,教程的相关信息的汇集
    HDU You Are the One (dp)
    HDU4291 A Short problem
    Mondriaan's Dream(poj2411)
    HDU 4277 USACO ORZ
    求欧拉回路的路径(usaco3.3Riding the Fences)
    poj2923 (状态压缩01背包)
  • 原文地址:https://www.cnblogs.com/pricks/p/3921625.html
Copyright © 2011-2022 走看看