保存在共享preferences自定义对象自定义、对象、存在、preferences

2023-09-08 09:29:11 作者:释然丶钟允浩

我要保存在共享preferences自定义对象 myObject的。该定制对象的ArrayList< anotherCustomObj> 。这 anotherCustomObj 的主要变量。

两个 myObject的 anotherCustomObj 是parcelable。

我试过低于code将其转换为字符串,并将其保存:

 字符串myStr的= gson.toJson(myObject的);
editor.putString(MY_OBJ,myStr的);
 

但它给RuntimeException的。

编辑:下面是logcat的屏幕截图。

anotherCustomObj实现:

 包com.objectlounge.ridesharebuddy.classes;

进口的java.io.File;
进口的java.io.InputStream;
进口java.text.ParseException;
进口java.text.SimpleDateFormat的;
进口的java.util.Calendar;
进口java.util.Date;
进口java.util.Locale中;

进口android.annotation.Sup pressLint;
进口android.content.Context;
进口android.content.Shared preferences;
进口android.content.Shared preferences.Editor;
进口android.graphics.Bitmap;
进口android.graphics.BitmapFactory;
进口android.os.Parcel;
进口android.os.Parcelable;
。进口的Andr​​oid preference preferenceManager。
进口android.util.Log;

进口com.google.gson.annotations.SerializedName;
进口com.objectlounge.ridesharebuddy.R;

公共类RS_SingleMatch实现Parcelable {

    私有静态最后弦乐RIDESHARE_DIRECTORY =RideShareBuddy;
    私有静态最后字符串变量=RS_SingleMatch;
    私有静态最后弦乐IMAGE_PATH =的ImagePath;
    私有静态最后弦乐IMAGE_NAME_ preFIX =RideShareBuddyUserImage;

    私人上下文的背景下;
    @SerializedName(ID)
    私人诠释用户id;
    私人诠释TRIPID;
    私人字符串IMAGEURL;
    @SerializedName(username的)
    私人字符串电子邮件;
    私人字符串真实姓名;
    私人字符串性别;
    私人诠释信誉;
    私人字符串createdAt;
    私人字符串的出生日期;
    私人浮动fromLat,fromLon,toLat,托隆;
    私人字符串fromPOI,toPOI;
    私人字符串departureTime;
    私人诠释matchStrength;

    //构造函数
    公共RS_SingleMatch(上下文的背景下){
        this.context =背景;
    }

    //构造从包裹再现物体时使用
    公共RS_SingleMatch(包裹中){
        readFromParcel(在);
    }

    @覆盖
    公众诠释describeContents(){
        返回0;
    }

    @覆盖
    //调用写所有变量包裹
    公共无效writeToParcel(包裹DEST,INT标志){

        dest.writeInt(用户id);
        dest.writeInt(TRIPID);
        dest.writeString(IMAGEURL);
        dest.writeString(电子邮件);
        dest.writeString(实名);
        dest.writeString(性别);
        dest.writeInt(声誉);
        dest.writeString(createdAt);
        dest.writeString(出生日期);
        dest.writeFloat(fromLat);
        dest.writeFloat(fromLon);
        dest.writeFloat(toLat);
        dest.writeFloat(托隆);
        dest.writeString(fromPOI);
        dest.writeString(toP​​OI);
        dest.writeString(departureTime);
        dest.writeInt(matchStrength);
    }

    //从构造函数调用来读取包裹对象属性
    私人无效readFromParcel(包裹中){

        //从包裹的所有变量中读取到创建的对象
        用户id = in.readInt();
        TRIPID = in.readInt();
        IMAGEURL = in.readString();
        电子邮件= in.readString();
        实名= in.readString();
        性别= in.readString();
        信誉= in.readInt();
        createdAt = in.readString();
        生日= in.readString();
        fromLat = in.readFloat();
        fromLon = in.readFloat();
        toLat = in.readFloat();
        托隆= in.readFloat();
        fromPOI = in.readString();
        toPOI = in.readString();
        departureTime = in.readString();
        matchStrength = in.readInt();
    }

    //这创造者用于创建新的对象或对象的阵列
    公共静态最终Parcelable.Creator< RS_SingleMatch> CREATOR =新Parcelable.Creator< RS_SingleMatch>(){

        @覆盖
        公共RS_SingleMatch createFromParcel(包裹中){
            返回新RS_SingleMatch(中);
        }

        @覆盖
        公共RS_SingleMatch [] newArray(INT尺寸){
            返回新RS_SingleMatch【尺寸】;
        }
    };

    //吸气剂
    公众诠释getUserId(){
        返回用户id;
    }

    公众诠释getTripId(){
        返回TRIPID;
    }

    公共字符串getImageUrl(){
        返回IMAGEURL;
    }

    公共位图的getImage(){

        位图图像= NULL;

        //如果IMAGEURL不为空
        如果(getImageUrl()长度()大于0){

            共享preferences preFS = preferenceManager
                    .getDefaultShared preferences(this.context);
            字符串的ImagePath = prefs.getString(IMAGE_PATH + getUserId(),);

            //从缓存图片
            如果((图像= RS_FileOperationsHelper.getImageAtPath(的ImagePath))== NULL){

                Log.d(TAG,图像在磁盘上没有找到。);
                线程t =新主题(新的Runnable(){

                    @覆盖
                    公共无效的run(){
                        //如果存储找不到图像,然后下载
                        setImage(downloadImage(getImageUrl()));
                    }
                });
                t.start();
            }

        } 其他 {
            //使用默认的图像
            图像= getDefaultProfileImage();
        }

        图象= RS_ImageViewHelper.getRoundededImage(图像,image.getWidth());
        Log.d(TAG,图像宽度:+ image.getWidth());
        返回形象;
    }

    公共字符串getEmail(){
        返回的电子邮件;
    }

    公共字符串getRealName(){
        回归真实姓名;
    }

    公共字符串getGender(){
        返回性别;
    }

    公众诠释getReputation(){
        返回声誉;
    }

    公共字符串getCreatedAt(){
        返回createdAt;
    }

    公共字符串getBirthdate(){
        返回出生日期;
    }

    公众持股量getFromLat(){
        返回fromLat;
    }

    公众持股量getFromLon(){
        返回fromLon;
    }

    公众持股量getToLat(){
        返回toLat;
    }

    公众持股量getToLon(){
        返回托隆;
    }

    公共字符串getFromPOI(){
        返回fromPOI;
    }

    公共字符串getToPOI(){
        返回toPOI;
    }

    公共字符串getDepartureTime(){
        返回departureTime;
    }

    公众诠释getMatchStrength(){
        返回matchStrength;
    }

    //塞特斯
    公共无效setContext(上下文的背景下){
        this.context =背景;
    }

    公共无效setUserId(INT用户id){
        this.userId =用户id;
    }

    公共无效setTripId(INT TRIPID){
        this.tripId = TRIPID;
    }

    公共无效setImageUrl(字符串IMAGEURL){
        this.imageUrl = IMAGEURL;
    }

    公共无效setImage(位图图片){

        如果(IMG!= NULL){

            //获取缓存目录的路径和追加RIDESHARE_DIRECTORY。
            字符串cacheDirStoragePath = context.getCacheDir()
                    +/
                    + RIDESHARE_DIRECTORY;

            //在cacheDirStoragePath创建目录,如果不存在。
            如果(RS_FileOperationsHelper
                    .createDirectoryAtPath(cacheDirStoragePath)){

                字符串的ImagePath = cacheDirStoragePath +/
                        + IMAGE_NAME_ preFIX + this.userId +巴纽;

                //保存新的图像缓存
                RS_FileOperationsHelper.saveImageAtPath(IMG,的ImagePath,this.context);

                共享preferences preF = preferenceManager
                        .getDefaultShared preferences(上下文);
                编辑E = pref.edit();
                e.putString(IMAGE_PATH + getUserId(),的ImagePath);
                e.commit();
            }
        }
    }

    公共无效setEmail(字符串电子邮件){
        this.email =电子邮件;
    }

    公共无效setRealName(字符串实名){
        this.realName =真实姓名;
    }

    公共无效setGender(字符串性别){
        this.gender =性别;
    }

    公共无效setReputation(INT口碑){
        this.reputation =声誉;
    }

    公共无效setCreatedAt(字符串createdAt){
        this.createdAt = createdAt;
    }

    公共无效setBirthdate(字符串生日){
        this.birthdate =出生日期;
    }

    公共无效setFromLat(浮动fromLat){
        this.fromLat = fromLat;
    }

    公共无效setFromLon(浮动fromLon){
        this.fromLon = fromLon;
    }

    公共无效setToLat(浮动toLat){
        this.toLat = toLat;
    }

    公共无效setToLon(浮点托隆){
        this.toLon =托隆;
    }

    公共无效setFromPOI(字符串fromPOI){
        this.fromPOI = fromPOI;
    }

    公共无效setToPOI(字符串toPOI){
        this.toPOI = toPOI;
    }

    公共无效setDepartureTime(字符串departureTime){
        this.departureTime = departureTime;
    }

    公共无效setMatchStrength(INT matchStrength){
        this.matchStrength = matchStrength;
    }

    //计算年龄利用给定的日期
    @燮pressLint(SimpleDateFormat的)
    公众诠释calculateAge(字符串日期){
        INT年龄= 0;
        尝试 {
            SimpleDateFormat的格式化=新的SimpleDateFormat(YYYY-MM-DD);
            日期bdate = formatter.parse(日期);
            日历LCAL = Calendar.getInstance();
            lCal.setTime(bdate);
            INT lYear = lCal.get(Calendar.YEAR);
            INT lMonth = lCal.get(Calendar.MONTH)+ 1;
            INT lDay = lCal.get(Calendar.DATE);

            日历DOB = Calendar.getInstance();
            今天的日历= Calendar.getInstance();

            dob.set(lYear,lMonth,lDay);

            年龄= today.get(Calendar.YEAR) -  dob.get(Calendar.YEAR);

            如果(today.get(Calendar.DAY_OF_YEAR)所述; dob.get(Calendar.DAY_OF_YEAR)){
                年龄 - ;
            }

        }赶上(ParseException的E){
            e.printStackTrace();
        }
        返回年龄;
    }

    //下载图像,如果不可用
    保护无效downloadAndSaveImage(){

        共享preferences preFS = preferenceManager
                .getDefaultShared preferences(this.context);
        字符串的ImagePath = prefs.getString(IMAGE_PATH + getUserId(),);
        档案文件=新的文件(的ImagePath);

        //如果映像路径没有存储在用户的默认值或图像不存在
        // 然后
        如果((的ImagePath ==空|| file.exists())及!&安培; this.imageUrl.length()大于0){

            //下载在单独的线程
            线程t =新主题(新的Runnable(){
                @覆盖
                公共无效的run(){
                    setImage(downloadImage(getImageUrl()));
                }
            });
            t.start();
        }
    }

    //下载图片
    私人位图downloadImage(字符串IMAGEURL){

        Log.d(TAG,图像URL:+ IMAGEURL);
        位图图像= NULL;

        尝试 {

            //下载网址的图像
            InputStream的时间=新的java.net.URL(imageUrl.trim())的OpenStream()。
            图像= BitmapFactory.de codeStream(中);

        }赶上(例外五){
            e.printStackTrace();
        }

        Log.d(TAG,图片下载完整的图像:+图像);

        返回形象;
    }

    //获取默认的图像
    受保护的位图getDefaultProfileImage(){

        位图图像= BitmapFactory.de codeResource(
                this.context.getResources(),R.drawable.default_male);

        如果(this.gender.toUpperCase(Locale.US).startsWith(F)){
            图像= BitmapFactory.de codeResource(this.context.getResources()
                    R.drawable.default_female);
        }

        返回形象;
    }
}
 

解决方案

链接张贴者达米安是有助于解决我的问题。但是,在我的情况出现在自定义对象没有视图组件。

据我观察,如果你找到ANY_VARIABLE_NAME 多JSON领域,那么很可能,这是因为GSON是不能转换的对象。你可以在下面code尝试解决这个问题。

为什么我用PS自定义的图片尺寸保存之后不一样

添加下面的类来告诉GSON保存和/或只检索那些谁序列化的名字声明的变量。

 类排除实现ExclusionStrategy {

    @覆盖
    公共布尔shouldSkipClass(类<>为arg0){
        // TODO自动生成方法存根
        返回false;
    }

    @覆盖
    公共布尔shouldSkipField(FieldAttributes场){
        SerializedName NS = field.getAnnotation(SerializedName.class);
        如果(NS!= NULL)
            返回false;
        返回true;
    }
}
 

下面是你需要保存/恢复的对象的类。 添加 @SerializedName 对于需要保存的变量和/或检索。

  MyClass类{
    @SerializedName(ID)
    INT ID;
    @SerializedName(名称)
    字符串名称;
}
 

code为myObject转换成jsonString:

 排除EX =新排除();
    GSON GSON =新GsonBuilder().addDeserializationExclusionStrategy(ex).addSerializationExclusionStrategy(ex).create();
字符串jsonString = gson.toJson(myObject的);
 

code,从jsonString得到的对象:

 排除EX =新排除();
GSON GSON =新GsonBuilder().addDeserializationExclusionStrategy(ex).addSerializationExclusionStrategy(ex).create();
MyClass的myObject的= gson.fromJson(jsonString,myClass.class);
 

I want to save a custom object myObject in shared preferences. Where this custom object has ArrayList<anotherCustomObj>. This anotherCustomObj has primary variables.

Both myObject and anotherCustomObj are parcelable.

I tried below code to convert it to String and save it :

String myStr = gson.toJson(myObject);
editor.putString(MY_OBJ, myStr);

But it gives RunTimeException.

EDIT : Below is logcat screen shot.

anotherCustomObj implementation :

package com.objectlounge.ridesharebuddy.classes;

import java.io.File;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.util.Log;

import com.google.gson.annotations.SerializedName;
import com.objectlounge.ridesharebuddy.R;

public class RS_SingleMatch implements Parcelable {

    private static final String RIDESHARE_DIRECTORY = "RideShareBuddy";
    private static final String TAG = "RS_SingleMatch";
    private static final String IMAGE_PATH = "imagePath";
    private static final String IMAGE_NAME_PREFIX = "RideShareBuddyUserImage";

    private Context context;
    @SerializedName("id")
    private int userId;
    private int tripId;
    private String imageUrl;
    @SerializedName("userName")
    private String email;
    private String realName;
    private String gender;
    private int reputation;
    private String createdAt;
    private String birthdate;
    private float fromLat, fromLon, toLat, toLon;
    private String fromPOI, toPOI;
    private String departureTime;
    private int matchStrength;

    // Constructor
    public RS_SingleMatch(Context context) {
        this.context = context;
    }

    // Constructor to use when reconstructing an object from a parcel
    public RS_SingleMatch(Parcel in) {
        readFromParcel(in);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    // Called to write all variables to a parcel
    public void writeToParcel(Parcel dest, int flags) {

        dest.writeInt(userId);
        dest.writeInt(tripId);
        dest.writeString(imageUrl);
        dest.writeString(email);
        dest.writeString(realName);
        dest.writeString(gender);
        dest.writeInt(reputation);
        dest.writeString(createdAt);
        dest.writeString(birthdate);
        dest.writeFloat(fromLat);
        dest.writeFloat(fromLon);
        dest.writeFloat(toLat);
        dest.writeFloat(toLon);
        dest.writeString(fromPOI);
        dest.writeString(toPOI);
        dest.writeString(departureTime);
        dest.writeInt(matchStrength);
    }

    // Called from constructor to read object properties from parcel
    private void readFromParcel(Parcel in) {

        // Read all variables from parcel to created object
        userId = in.readInt();
        tripId = in.readInt();
        imageUrl = in.readString();
        email = in.readString();
        realName = in.readString();
        gender = in.readString();
        reputation = in.readInt();
        createdAt = in.readString();
        birthdate = in.readString();
        fromLat = in.readFloat();
        fromLon = in.readFloat();
        toLat = in.readFloat();
        toLon = in.readFloat();
        fromPOI = in.readString();
        toPOI = in.readString();
        departureTime = in.readString();
        matchStrength = in.readInt();
    }

    // This creator is used to create new object or array of objects
    public static final Parcelable.Creator<RS_SingleMatch> CREATOR = new Parcelable.Creator<RS_SingleMatch>() {

        @Override
        public RS_SingleMatch createFromParcel(Parcel in) {
            return new RS_SingleMatch(in);
        }

        @Override
        public RS_SingleMatch[] newArray(int size) {
            return new RS_SingleMatch[size];
        }
    };

    // Getters
    public int getUserId() {
        return userId;
    }

    public int getTripId() {
        return tripId;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public Bitmap getImage() {

        Bitmap image = null;

        // If imageUrl is not empty
        if (getImageUrl().length() > 0) {

            SharedPreferences prefs = PreferenceManager
                    .getDefaultSharedPreferences(this.context);
            String imagePath = prefs.getString(IMAGE_PATH + getUserId(), "");

            // Get image from cache
            if ((image = RS_FileOperationsHelper.getImageAtPath(imagePath)) == null) {

                Log.d(TAG, "Image not found on disk.");
                Thread t = new Thread(new Runnable() {

                    @Override
                    public void run() {
                        // If image not found on storage then download it
                        setImage(downloadImage(getImageUrl()));
                    }
                });
                t.start();
            }

        } else {
            // Use default image
            image = getDefaultProfileImage();
        }

        image = RS_ImageViewHelper.getRoundededImage(image, image.getWidth());
        Log.d(TAG, "Image width : " + image.getWidth());
        return image;
    }

    public String getEmail() {
        return email;
    }

    public String getRealName() {
        return realName;
    }

    public String getGender() {
        return gender;
    }

    public int getReputation() {
        return reputation;
    }

    public String getCreatedAt() {
        return createdAt;
    }

    public String getBirthdate() {
        return birthdate;
    }

    public float getFromLat() {
        return fromLat;
    }

    public float getFromLon() {
        return fromLon;
    }

    public float getToLat() {
        return toLat;
    }

    public float getToLon() {
        return toLon;
    }

    public String getFromPOI() {
        return fromPOI;
    }

    public String getToPOI() {
        return toPOI;
    }

    public String getDepartureTime() {
        return departureTime;
    }

    public int getMatchStrength() {
        return matchStrength;
    }

    // Setters
    public void setContext(Context context) {
        this.context = context;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public void setTripId(int tripId) {
        this.tripId = tripId;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }

    public void setImage(Bitmap img) {

        if (img != null) {

            // Get cache directory's path and append RIDESHARE_DIRECTORY.
            String cacheDirStoragePath = context.getCacheDir()
                    + "/"
                    + RIDESHARE_DIRECTORY;

            // Create directory at cacheDirStoragePath if does not exist.
            if (RS_FileOperationsHelper
                    .createDirectoryAtPath(cacheDirStoragePath)) {

                String imagePath = cacheDirStoragePath + "/"
                        + IMAGE_NAME_PREFIX + this.userId + ".png";

                // Save new image to cache
                RS_FileOperationsHelper.saveImageAtPath(img, imagePath, this.context);

                SharedPreferences pref = PreferenceManager
                        .getDefaultSharedPreferences(context);
                Editor e = pref.edit();
                e.putString(IMAGE_PATH + getUserId(), imagePath);
                e.commit();
            }
        }
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void setReputation(int reputation) {
        this.reputation = reputation;
    }

    public void setCreatedAt(String createdAt) {
        this.createdAt = createdAt;
    }

    public void setBirthdate(String birthdate) {
        this.birthdate = birthdate;
    }

    public void setFromLat(float fromLat) {
        this.fromLat = fromLat;
    }

    public void setFromLon(float fromLon) {
        this.fromLon = fromLon;
    }

    public void setToLat(float toLat) {
        this.toLat = toLat;
    }

    public void setToLon(float toLon) {
        this.toLon = toLon;
    }

    public void setFromPOI(String fromPOI) {
        this.fromPOI = fromPOI;
    }

    public void setToPOI(String toPOI) {
        this.toPOI = toPOI;
    }

    public void setDepartureTime(String departureTime) {
        this.departureTime = departureTime;
    }

    public void setMatchStrength(int matchStrength) {
        this.matchStrength = matchStrength;
    }

    // calculates age using given date
    @SuppressLint("SimpleDateFormat")
    public int calculateAge(String date) {
        int age = 0;
        try {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            Date bdate = formatter.parse(date);
            Calendar lCal = Calendar.getInstance();
            lCal.setTime(bdate);
            int lYear = lCal.get(Calendar.YEAR);
            int lMonth = lCal.get(Calendar.MONTH) + 1;
            int lDay = lCal.get(Calendar.DATE);

            Calendar dob = Calendar.getInstance();
            Calendar today = Calendar.getInstance();

            dob.set(lYear, lMonth, lDay);

            age = today.get(Calendar.YEAR) - dob.get(Calendar.YEAR);

            if (today.get(Calendar.DAY_OF_YEAR) < dob.get(Calendar.DAY_OF_YEAR)) {
                age--;
            }

        } catch (ParseException e) {
            e.printStackTrace();
        }
        return age;
    }

    // Download image if not available
    protected void downloadAndSaveImage() {

        SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(this.context);
        String imagePath = prefs.getString(IMAGE_PATH + getUserId(), "");
        File file = new File(imagePath);

        // If image path not stored in user defaults or image does not exists
        // then
        if ((imagePath == null || !file.exists()) && this.imageUrl.length() > 0) {

            // Download on separate thread
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    setImage(downloadImage(getImageUrl()));
                }
            });
            t.start();
        }
    }

    // Download an image
    private Bitmap downloadImage(String imageUrl) {

        Log.d(TAG, "Image url : " + imageUrl);
        Bitmap image = null;

        try {

            // Download an image from url
            InputStream in = new java.net.URL(imageUrl.trim()).openStream();
            image = BitmapFactory.decodeStream(in);

        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.d(TAG, "Image downloading complete. image : " + image);

        return image;
    }

    // Get default image
    protected Bitmap getDefaultProfileImage() {

        Bitmap image = BitmapFactory.decodeResource(
                this.context.getResources(), R.drawable.default_male);

        if (this.gender.toUpperCase(Locale.US).startsWith("F")) {
            image = BitmapFactory.decodeResource(this.context.getResources(),
                    R.drawable.default_female);
        }

        return image;
    }
}

解决方案

Link posted by damian was helpful to solve my problem. However, in my case there was no view component in custom object.

According to my observation if you find multiple JSON fields for ANY_VARIABLE_NAME, then it is likely that it is because GSON is not able to convert the object. And you can try below code to solve it.

Add below class to to tell GSON to save and/or retrieve only those variables who have Serialized name declared.

class Exclude implements ExclusionStrategy {

    @Override
    public boolean shouldSkipClass(Class<?> arg0) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean shouldSkipField(FieldAttributes field) {
        SerializedName ns = field.getAnnotation(SerializedName.class);
        if(ns != null)
            return false;
        return true;
    }
}

Below is the class whose object you need to save/retrieve. Add @SerializedName for variables that needs to saved and/or retrieved.

class myClass {
    @SerializedName("id")
    int id;
    @SerializedName("name")
    String name;
}

Code to convert myObject to jsonString :

Exclude ex = new Exclude();
    Gson gson = new GsonBuilder().addDeserializationExclusionStrategy(ex).addSerializationExclusionStrategy(ex).create();
String jsonString = gson.toJson(myObject);

Code to get object from jsonString :

Exclude ex = new Exclude();
Gson gson = new GsonBuilder().addDeserializationExclusionStrategy(ex).addSerializationExclusionStrategy(ex).create();
myClass myObject = gson.fromJson(jsonString, myClass.class);

 
精彩推荐
图片推荐