Android 显示获取服务器的超大图片 <19>

本文探讨了一种通过裁剪而非压缩图片来减小其大小并提高加载速度的方法,同时保持了图片的清晰度。具体介绍了使用MD5加密工具类和裁剪压缩类DurianBitmapCompress实现图片优化的过程。该方法适用于网络获取的图片,并通过保存到SD卡、压缩和返回显示用的Bitmap进行操作。同时,提到了考虑使用DiskLruCache策略以进一步优化大图片处理。

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

最近看了网上面很多博客或者APP转发较多的一篇blog,说再也不用当心从服务器上面获取的图片有多大了,都能够轻松显示出来,不知道是不是没有仔细看那篇文章,还是什么,没有特别验证,感觉很奇怪,他不是通过压缩图片的方式显示,而是通过裁剪图片的方式然后显示出来,通过裁剪的方式压缩图片大小,个人觉得很奇怪,裁剪过的图片还有什么用呢?

个人结合前面的一篇博客,通过压缩的办法,然后在结合在网上面看了一些推荐的办法.

在没有去考虑DiskLruCache的方式,我粗略的操作如下:

首先提供一个MD5的工具类:DurianMD5.java

package org.durian.durianhttpresponsecache.bitmapcompress;

import java.security.MessageDigest;

/**
 * Project name : DurianHttpResponseCache
 * Created by zhibao.liu on 2016/1/29.
 * Time : 17:56
 * Email warden_sprite@foxmail.com
 * Action : durian
 */
public class DurianMD5 {

    /**
     * MD5加密
     * @param str 要加密的字符串
     * @return 加密后的字符串
     */
    public static String md5(String str) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        char[] charArray = str.toCharArray();
        byte[] byteArray = new byte[charArray.length];
        for (int i = 0; i < charArray.length; i++) {
            byteArray[i] = (byte) charArray[i];
        }
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

}

然后下面是一个DurianBitmapCompress.java

package org.durian.durianhttpresponsecache.bitmapcompress;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.os.Environment;

import org.durian.durianhttpresponsecache.R;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Project name : DurianHttpResponseCache
 * Created by zhibao.liu on 2016/1/29.
 * Time : 17:54
 * Email warden_sprite@foxmail.com
 * Action : durian
 */
public class DurianBitmapCompress {

    final String PATH = Environment.getExternalStorageDirectory()
            + "/durian.jpg";

    public static Bitmap getCompressNetBitmap(Bitmap bitmap, int bitmapMaxWidth) throws Exception {

        String imagePath=saveToLocal(bitmap);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imagePath, options);

        int height = options.outHeight;
        int width = options.outWidth;
        int reqHeight = 0;
        int reqWidth = bitmapMaxWidth;
        reqHeight = (reqWidth * height)/width;
        // 在内存中创建bitmap对象,这个对象按照缩放大小创建的
        options.inSampleSize = calculateInSampleSize(options, bitmapMaxWidth, reqHeight);
        options.inJustDecodeBounds = false;
        Bitmap map = BitmapFactory.decodeFile(imagePath, options);

        Bitmap retmap = compressImage(Bitmap.createScaledBitmap(map, bitmapMaxWidth, reqHeight, false));

        /*String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        saveImg(bbb, DurianMD5.md5(timeStamp));*/

        return retmap;

    }
    /*
    * how to use following code :
    * getCompressBitmap(context,480);
    * */
    public static Bitmap getCompressBitmap(Context context,int bitmapMaxWidth,int resID) throws Exception {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
//        BitmapFactory.decodeFile(oldPath, options);
        BitmapFactory.decodeResource(context.getResources(),resID,options);

        int height = options.outHeight;
        int width = options.outWidth;
        int reqHeight = 0;
        int reqWidth = bitmapMaxWidth;
        reqHeight = (reqWidth * height)/width;
        // 在内存中创建bitmap对象,这个对象按照缩放大小创建的
        options.inSampleSize = calculateInSampleSize(options, bitmapMaxWidth, reqHeight);
        options.inJustDecodeBounds = false;
//        Bitmap bitmap = BitmapFactory.decodeFile(oldPath, options);
        Bitmap bitmap =BitmapFactory.decodeResource(context.getResources(),resID,options);
        //Log.e("asdasdas", "reqWidth->"+reqWidth+"---reqHeight->"+reqHeight);
        Bitmap retmap = compressImage(Bitmap.createScaledBitmap(bitmap, bitmapMaxWidth, reqHeight, false));

        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());

//        saveImg(bbb, DurianMD5.md5(timeStamp));

        return retmap;
    }

    private static String getThumbUpFromDrawable(Context context, int bitmapMaxWidth) throws Exception {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
//        BitmapFactory.decodeFile(oldPath, options);
        BitmapFactory.decodeResource(context.getResources(),R.drawable.large,options);

        int height = options.outHeight;
        int width = options.outWidth;
        int reqHeight = 0;
        int reqWidth = bitmapMaxWidth;
        reqHeight = (reqWidth * height)/width;
        // 在内存中创建bitmap对象,这个对象按照缩放大小创建的
        options.inSampleSize = calculateInSampleSize(options, bitmapMaxWidth, reqHeight);
        options.inJustDecodeBounds = false;
//        Bitmap bitmap = BitmapFactory.decodeFile(oldPath, options);
        Bitmap bitmap =BitmapFactory.decodeResource(context.getResources(),R.drawable.large,options);
        //Log.e("asdasdas", "reqWidth->"+reqWidth+"---reqHeight->"+reqHeight);
        Bitmap retmap = compressImage(Bitmap.createScaledBitmap(bitmap, bitmapMaxWidth, reqHeight, false));
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        return saveImg(retmap, DurianMD5.md5(timeStamp));
    }

    /*
    * how to use following code :
    * getThumbUploadPath(PATH,480);
    * */

    private static String getThumbUploadPath(String oldPath,int bitmapMaxWidth) throws Exception {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(oldPath, options);
        int height = options.outHeight;
        int width = options.outWidth;
        int reqHeight = 0;
        int reqWidth = bitmapMaxWidth;
        reqHeight = (reqWidth * height)/width;
        // 在内存中创建bitmap对象,这个对象按照缩放大小创建的
        options.inSampleSize = calculateInSampleSize(options, bitmapMaxWidth, reqHeight);
        options.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile(oldPath, options);
        //Log.e("asdasdas", "reqWidth->"+reqWidth+"---reqHeight->"+reqHeight);
        Bitmap retmap = compressImage(Bitmap.createScaledBitmap(bitmap, bitmapMaxWidth, reqHeight, false));
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        return saveImg(retmap, DurianMD5.md5(timeStamp));
    }

    private static int calculateInSampleSize(BitmapFactory.Options options,
                                      int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float) height / (float) reqHeight);
            } else {
                inSampleSize = Math.round((float) width / (float) reqWidth);
            }
        }
        return inSampleSize;
    }

    private static Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 80, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
            options -= 10;// 每次都减少10
            baos.reset();// 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
        return bitmap;
    }

    public static String saveToLocal(Bitmap map) throws Exception {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        return saveImg(map, DurianMD5.md5(timeStamp));
    }

    public static String saveImg(Bitmap b,String name) throws Exception{
        String path = Environment.getExternalStorageDirectory().getPath()+File.separator+"";
        File mediaFile = new File(path + File.separator + name + ".jpg");
        if(mediaFile.exists()){
            mediaFile.delete();

        }
        if(!new File(path).exists()){
            new File(path).mkdirs();
        }
        mediaFile.createNewFile();
        FileOutputStream fos = new FileOutputStream(mediaFile);
        b.compress(Bitmap.CompressFormat.PNG, 100, fos);
        fos.flush();
        fos.close();
        /*b.recycle();
        b = null;
        System.gc();*/
        return mediaFile.getPath();
    }

}

上面的程序提供了很多API接口以便适应不同的环境.上面的程序需要注意几个地方:

第一个: 在保存的地方,下面如果最后一步是保存,图片不用于显示和其他用,就不需要注释下面的,以便回收memory,防止内存泄露,但是如果保存后,后面还要使用图片切记要屏蔽掉.

/*b.recycle();
        b = null;
        System.gc();*/

第二个:下面的这个方式从服务器获取图片后,先保存在sdcard目录下,然后对其提出压缩并且返回作为显示的Bitmap.

public static Bitmap getCompressNetBitmap(Bitmap bitmap, int bitmapMaxWidth)


网络获取:

if(connection.getResponseCode()==HttpURLConnection.HTTP_OK){

                        InputStream is=connection.getInputStream();
                        bitmap= BitmapFactory.decodeStream(is);
                        try {
                            bitmap=DurianBitmapCompress.getCompressNetBitmap(bitmap,450);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }

获取了以后通过发送一个Handler消息,更新图片.

刚才说了如果不考虑DiskLruCache,就直接保存在一个临时目录中,但是一般超大图片都会考虑使用DiskLruCache策略.DiskLruCache策略下一篇解释.








package com.example.kucun2.entity.data; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.Log; import com.example.kucun2.entity.*; import com.example.kucun2.function.MyAppFnction; import com.example.kucun2.function.SafeLogger; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.*; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class Data { // 数据集合声明(保持原有属性名不变) public static SynchronizedList<Bancai> bancais = new SynchronizedList<>(Bancai.class); public static SynchronizedList<Caizhi> caizhis = new SynchronizedList<>(Caizhi.class); public static SynchronizedList<Mupi> mupis = new SynchronizedList<>(Mupi.class); public static SynchronizedList<Chanpin> chanpins = new SynchronizedList<>(Chanpin.class); public static SynchronizedList<Chanpin_Zujian> chanpin_zujians = new SynchronizedList<>(Chanpin_Zujian.class); public static SynchronizedList<Dingdan> dingdans = new SynchronizedList<>(Dingdan.class); public static SynchronizedList<Dingdan_Chanpin> dingdan_chanpins = new SynchronizedList<>(Dingdan_Chanpin.class); public static SynchronizedList<Dingdan_chanpin_zujian> Dingdan_chanpin_zujians = new SynchronizedList<>(Dingdan_chanpin_zujian.class); public static SynchronizedList<Kucun> kucuns = new SynchronizedList<>(Kucun.class); public static SynchronizedList<Zujian> zujians = new SynchronizedList<>(Zujian.class); public static SynchronizedList<User> users = new SynchronizedList<>(User.class); public static SynchronizedList<Jinhuo> jinhuos = new SynchronizedList<>(Jinhuo.class); public static final Map<Class,SynchronizedList<SynchronizableEntity>> dataCollectionMap=new HashMap<>(); private static final Gson gson = new Gson(); private static OkHttpClient client ; private static final String TAG = "DataLoader"; static { // 静态初始化块:在类加载时执行,保证所有静态字段已初始化 try { Field[] fields = Data.class.getDeclaredFields(); for (Field field : fields) { if (SynchronizedList.class.isAssignableFrom(field.getType())) { // 获取泛型类型参数 ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType(); Class<?> entityType = (Class<?>) parameterizedType.getActualTypeArguments()[0]; // 创建 SynchronizedList 并设置实体类型 SynchronizedList<?> list = new SynchronizedList<>((Class<SynchronizableEntity>) entityType); field.set(null, list); // 将列表添加到 dataCollectionMap if (list != null) { dataCollectionMap.put(entityType, (SynchronizedList<SynchronizableEntity>) list); } } } } catch (IllegalAccessException e) { throw new RuntimeException("初始化dataCollectionMap失败", e); } } public static void loadAllData(Context context, LoadDataCallback callback) { if (Looper.myLooper() != Looper.getMainLooper()) { throw new IllegalStateException("Data.loadAllData must be called on main thread"); } // 确保使用安全的客户端 if (client == null) { client= MyAppFnction.getClient(); } //禁用同步 SynchronizableEntity.setSyncEnabled(false); String url = MyAppFnction.getStringResource("string", "url") + MyAppFnction.getStringResource("string", "url_all"); Log.d("url", "loadAllData: " + url); Request request = new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e(TAG, "Failed to load data", e); SynchronizableEntity.setSyncEnabled(true); if (callback != null)safeCallback(callback, false); } @Override public void onResponse(Call call, Response response) throws IOException { if (!response.isSuccessful()) { Log.e(TAG, "Unexpected response code: " + response.code()); if (callback != null) safeCallback(callback, false); return; } String responseData = response.body().string(); SynchronizableEntity.setSyncEnabled(true); ensurePreservedObjects(); parseAndAssignData(responseData, context, callback); } }); } // 解析并赋值数据 private static void parseAndAssignData(String jsonData, Context context, LoadDataCallback callback) { // 创建包含所有数据类型的TypeToken ensurePreservedObjects(); Type informationType = new TypeToken<Information<AllDataResponse>>(){}.getType(); Information<AllDataResponse> information = gson.fromJson(jsonData, informationType); Log.e(TAG, "Invalid response data"+jsonData); if (information == null || information.getData() == null || information.getStatus() != 200) { Log.e(TAG, "Invalid response data"); if (callback != null) callback.onFailure(); return; } AllDataResponse allData = information.getData(); SafeLogger.d("data","数据:"+gson.toJson(allData)); safeInitializeList(allData.bancais); safeInitializeList(allData.caizhis); safeInitializeList(allData.mupis); safeInitializeList(allData.chanpins); safeInitializeList(allData.chanpin_zujians); safeInitializeList(allData.dingdans); safeInitializeList(allData.dingdan_chanpins); safeInitializeList(allData.Dingdan_chanpin_zujians); safeInitializeList(allData.kucuns); safeInitializeList(allData.zujians); safeInitializeList(allData.users); safeInitializeList(allData.jinhuos); SafeLogger.d("data","数据:非空"+gson.toJson(allData)); // 赋值到对应的列表(使用安全方法保持已有引用) updateList(bancais, allData.bancais); updateList(caizhis, allData.caizhis); updateList(mupis, allData.mupis); updateList(chanpins, allData.chanpins); updateList(chanpin_zujians, allData.chanpin_zujians); updateList(dingdans, allData.dingdans); updateList(dingdan_chanpins, allData.dingdan_chanpins); updateList(Dingdan_chanpin_zujians, allData.Dingdan_chanpin_zujians); updateList(kucuns, allData.kucuns); updateList(zujians, allData.zujians); updateList(users, allData.users); updateList(jinhuos, allData.jinhuos); SafeLogger.d("data","数据:data.bancais"+gson.toJson(Data.bancais)); // 在设置引用关系前关闭同步 SynchronizableEntity.setSyncEnabled(false); Log.d("DataParse", "开始解析JSON数据"); resolveReferences(); Log.d("DataParse", "解析完成,实体关系建立"); // 为所有实体设置正确状态(已存在服务器) setAllEntitiesState(SynchronizableEntity.SyncState.MODIFIED); ensurePreservedObjects(); // 启用同步 SynchronizableEntity.setSyncEnabled(true); if (callback != null) callback.onSuccess(); } public static void safeCallback(LoadDataCallback callback, boolean success) { new Handler(Looper.getMainLooper()).post(() -> { if (success) { callback.onSuccess(); } else { callback.onFailure(); } }); } // 更新列表内容但保持对象引用不变 private static <T extends SynchronizableEntity> void updateList(List<T> existingList, List<T> newList) { if (newList == null) return; // 创建临时列表保留预置对象 List<T> preservedObjects = new ArrayList<>(); for (T item : existingList) { if (item != null && item.isPreservedObject()) { preservedObjects.add(item); } } // 清除原有列表并添加保留对象 existingList.clear(); existingList.addAll(preservedObjects); // 添加新数据,跳过预置对象的ID for (T newItem : newList) { if (newItem.getId() != null && newItem.getId() != -1) { existingList.add(newItem); } } } // 添加确保预置对象存在的方法 private static void ensurePreservedObjects() { if (!containsPreservedObject(bancais)) bancais.add(createInstance(Bancai.class)); if (!containsPreservedObject(caizhis)) caizhis.add(createInstance(Caizhi.class)); if (!containsPreservedObject(mupis)) mupis.add(createInstance(Mupi.class)); if (!containsPreservedObject(chanpins)) chanpins.add(createInstance(Chanpin.class)); if (!containsPreservedObject(chanpin_zujians)) chanpin_zujians.add(createInstance(Chanpin_Zujian.class)); if (!containsPreservedObject(dingdans)) dingdans.add(createInstance(Dingdan.class)); if (!containsPreservedObject(kucuns)) kucuns.add(createInstance(Kucun.class)); if (!containsPreservedObject(zujians)) zujians.add(createInstance(Zujian.class)); if (!containsPreservedObject(Dingdan_chanpin_zujians)) Dingdan_chanpin_zujians.add(createInstance(Dingdan_chanpin_zujian.class)); if (!containsPreservedObject(dingdan_chanpins)) dingdan_chanpins.add(createInstance(Dingdan_Chanpin.class)); if (!containsPreservedObject(jinhuos)) jinhuos.add(createInstance(Jinhuo.class)); if (!containsPreservedObject(users)) users.add(createInstance(User.class)); // 为其他需要预置对象的列表添加... try { setDefaultAssociation(bancais); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } // 检查列表是否包含预置对象 private static <T extends SynchronizableEntity> boolean containsPreservedObject(List<T> list) { for (T item : list) { if (item != null && item.isPreservedObject()) { Log.d(TAG, "containsPreservedObject: "+item.getId()); item= (T) createInstance(item.getClass()); return true; } } return !list.isEmpty(); } private static <T extends SynchronizableEntity> void setDefaultAssociation(SynchronizedList<T> e ) throws IllegalAccessException, ClassNotFoundException { for (T t:e) { Class clazz=t.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field f:fields){ f.setAccessible(true); Class s=f.getType(); if(SynchronizableEntity.class.isAssignableFrom(s)){ if (t.getId()<0 ||f.get(t)==null|| ((SynchronizableEntity)f.get(t)).getId()==null) { f.set(t, dataCollectionMap.get(s).get(-1)); }else { f.set(t, dataCollectionMap.get(s).get( ((SynchronizableEntity)f.get(t)).getId())); } } if (List.class.isAssignableFrom(s)){ Type genericSuperclass = s.getGenericSuperclass(); if (genericSuperclass instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) genericSuperclass; Type[] types = pt.getActualTypeArguments(); System.out.println("集合类型: " + types[0].getTypeName()); // User Class c=Class.forName(types[0].getTypeName()); if(SynchronizableEntity.class.isAssignableFrom(c)) { List<SynchronizableEntity> l = (List<SynchronizableEntity>) f.get(t); if (l == null) { l = new ArrayList(); } if (l.isEmpty() || t.getId() < 0) { l.add(dataCollectionMap.get(c).get(-1)); } if (!l.isEmpty()) { for (int i = 0; i < l.size(); i++) { l.set(i,dataCollectionMap.get(c).get( l.get(i).getId())); } } } } } } } } /** * 根据传入的Class对象创建对应类型的实例 * @param clazz 目标类型对应的Class对象 * @param <T> 目标类型泛型参数 * @return 指定类型的实例 */ public static <T> T createInstance(Class<T> clazz) { try { // 通过反射调用无参构造函数创建实例 T g=clazz.getDeclaredConstructor().newInstance(); // Log.d("g",""+g); Field[] fields = clazz.getDeclaredFields(); for (Field f: fields ) { f.setAccessible(true); if(f.getType().equals(String.class)){ f.set(g,"无"); } if(f.getType().equals(Integer.class)){ f.set(g,-1); }if(f.getType().equals(Double.class)){ f.set(g,-1.0); } if (f.getType().equals(Date.class)){ f.set(g,new Date()); } } Log.d("g",""+gson.toJson(g)); clazz.getMethod("setId",Integer.class).invoke(g,-1); clazz.getMethod("setState", SynchronizableEntity. SyncState.class) .invoke(g,SynchronizableEntity.SyncState.PRESERVED); return g; } catch (Exception e) { Log.d(TAG, "createInstance: "+e.getLocalizedMessage()); throw new RuntimeException("创建实例失败: " + clazz.getName(), e); } } // // 创建预置板材对象 // private static<T> T createPreservedBancai(Class<T> t) { // Bancai preserved = new Bancai(); // preserved.setId(-1); // preserved.setState(SynchronizableEntity.SyncState.PRESERVED); // return preserved; // } // 解析对象间的引用关系(使用ID关联) private static void resolveReferences() { // 创建ID到对象的映射 Map<Integer, Bancai> bancaiMap = createIdMap(bancais); Map<Integer, Caizhi> caizhiMap = createIdMap(caizhis); Map<Integer, Mupi> mupiMap = createIdMap(mupis); Map<Integer, Chanpin> chanpinMap = createIdMap(chanpins); Map<Integer, Zujian> zujianMap = createIdMap(zujians); Map<Integer, Dingdan> dingdanMap = createIdMap(dingdans); Map<Integer, Kucun> kucunMap = createIdMap(kucuns); Log.d("RefResolution", "开始解析实体关系..."); // 解析Bancai引用 for (Bancai bancai : bancais) { if (bancai.getCaizhi() != null) { bancai.setCaizhi(caizhiMap.get(bancai.getCaizhi().getId())); } if (bancai.getMupi1() != null) { bancai.setMupi1(mupiMap.get(bancai.getMupi1().getId())); } if (bancai.getMupi2() != null) { bancai.setMupi2(mupiMap.get(bancai.getMupi2().getId())); } } // 解析Kucun引用 for (Kucun kucun : kucuns) { if(kucun==null)break; if (kucun.getBancai() != null) { kucun.setBancai(bancaiMap.get(kucun.getBancai().getId())); } } // 解析订单相关的嵌套对象 for (Dingdan_Chanpin dc : dingdan_chanpins) { if(dc==null)break; if (dc.getDingdan() != null) { dc.setDingdan(dingdanMap.get(dc.getDingdan().getId())); } if (dc.getChanpin() != null) { dc.setChanpin(chanpinMap.get(dc.getChanpin().getId())); } } // 解析产品相关的嵌套对象 for (Chanpin_Zujian cz : chanpin_zujians) { if(cz==null)break; if (cz.getChanpin() != null) { cz.setChanpin(chanpinMap.get(cz.getChanpin().getId())); } if (cz.getZujian() != null) { cz.setZujian(zujianMap.get(cz.getZujian().getId())); } if (cz.getBancai() != null) { cz.setBancai(bancaiMap.get(cz.getBancai().getId())); } } // 解析库存关联 for (Kucun k : kucuns) { if(k==null)break; if (k.getBancai() != null) { k.setBancai(bancaiMap.get(k.getBancai().getId())); } } // 添加缺失的实体关系解析 for (Dingdan_chanpin_zujian dm : Dingdan_chanpin_zujians) { if (dm.getZujian() != null) { // 确保组件和板材关联 dm.setZujian(chanpin_zujians.stream() .filter(cz -> cz.getId().equals(dm.getZujian().getId())) .findFirst().orElse(null)); if (dm.getBancai() != null) { dm.setBancai(bancais.stream() .filter(b -> b.getId().equals(dm.getBancai().getId())) .findFirst().orElse(null)); } } } } // 创建ID到对象的映射 private static <T extends EntityClassGrassrootsid> Map<Integer, T> createIdMap(List<T> list) { return createSafeIdMap(list); } // 回调接口 public interface LoadDataCallback { void onSuccess(); void onFailure(); } // 确保列表不为null private static <T> void safeInitializeList(List<T> list) { if (list == null) { list = new ArrayList<>(); } } // 安全创建ID映射 private static <T extends EntityClassGrassrootsid> Map<Integer, T> createSafeIdMap(List<T> list) { Map<Integer, T> map = new HashMap<>(); if (list != null) { for (T item : safeIterable(list)) { if (item != null && item.getId() != null) { map.put(item.getId(), item); } } } return map; } // 安全迭代方法(处理空集合) private static <T> Iterable<T> safeIterable(List<T> list) { return list != null ? list : Collections.emptyList(); } // 内部类用于解析JSON响应 public static class AllDataResponse { public List<Bancai> bancais; public List<Caizhi> caizhis; public List<Mupi> mupis; public List<Chanpin> chanpins; public List<Chanpin_Zujian> chanpin_zujians; public List<Dingdan> dingdans; public List<Dingdan_Chanpin> dingdan_chanpins; public List<Dingdan_chanpin_zujian> Dingdan_chanpin_zujians; public List<Kucun> kucuns; public List<Zujian> zujians; public List<User> users; public List<Jinhuo> jinhuos; } // 新增方法:设置所有实体状态 private static void setAllEntitiesState(SynchronizableEntity.SyncState state) { setListState(bancais, state); setListState(caizhis, state); setListState(mupis, state); setListState(Dingdan_chanpin_zujians, state); setListState(dingdans, state); setListState(chanpins, state); setListState(chanpin_zujians, state); setListState(zujians, state); setListState(jinhuos, state); setListState(kucuns, state); setListState(users, state); setListState(caizhis, state); // ... 其他列表 } private static <T extends SynchronizableEntity> void setListState(List<T> list, SynchronizableEntity.SyncState state) { for (T entity : list) { entity.setState(state); } } } E FATAL EXCEPTION: main Process: com.example.kucun2, PID: 21888 java.lang.ExceptionInInitializerError at com.example.kucun2.MainActivity.loadAppData(MainActivity.java:100) at com.example.kucun2.MainActivity.onCreate(MainActivity.java:31) at android.app.Activity.performCreate(Activity.java:9441) at android.app.Activity.performCreate(Activity.java:9387) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1526) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4644) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4876) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:112) at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:220) at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:148) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:120) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:3102) at android.os.Handler.dispatchMessage(Handler.java:109) at android.os.Looper.loopOnce(Looper.java:250) at android.os.Looper.loop(Looper.java:340) at android.app.ActivityThread.main(ActivityThread.java:9913) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:621) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957) Caused by: java.lang.IllegalArgumentException: Entity type cannot be null at com.example.kucun2.entity.data.SynchronizedList.<init>(SynchronizedList.java:35) at com.example.kucun2.entity.data.Data.<clinit>(Data.java:26) ... 19 more
最新发布
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值