android – ListView – ImageLoader在向上滚动时移动列表/项目

我正在寻找答案半天,但我找不到任何东西,虽然我认为这是一个常见的问题.我的问题:
我有一个ListView,它有不同大小(高度)的项目.每个项目都包含一个 ImageView.此 ImageView的图像由ImageLoader类在后台加载:
imageLoader.displayImage(url,holder.image);

如果我向下滚动ListView一切正常.图像被加载并显示(当然在屏幕/列表的底部).

但是如果我向上滚动并且图像不再存储在缓存中,那么ImageLoader必须重新加载图像,ListView跳转/项目被移动.我认为这是因为在列表顶部创建了一个新的View,其ImageView的高度为0dp.如果图像已加载并设置为ImageView,则ImageView的高度会自动从0dp更改为图像的大小.我认为这会推动ListView.

如果设置了图像,我尝试保存ImageViews的高度,然后将在顶部创建的ImageView的高度设置为保存的高度.但没有成功..

我不知道你是否能理解我的问题:D我希望如此:)

感谢,并有一个愉快的一天!

编辑:添加了ImageLoader类

public class ImageLoader {

MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
int size;
Context context;
private Map<ImageView,String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView,String>());
private HashMap<String,Integer> imagesSizes; 
ExecutorService executorService;
Handler handler=new Handler();//handler to display images in UI thread

public ImageLoader(Context context,int size){
    fileCache=new FileCache(context);
    this.context = context;
    executorService=Executors.newFixedThreadPool(5);
    this.size = size;
    imagesSizes = new HashMap<String,Integer>();
}

final int stub_id=R.color.transparent;
public void displayImage(String url,ImageView imageView)
{
    imageViews.put(imageView,url);
    Bitmap bitmap=memoryCache.get(url);
    if(bitmap!=null){
        imageView.setimageBitmap(bitmap);
        saveImageSize(imageView,url);
    }   
    else
    {
        queuePhoto(url,imageView);
        imageView.setimageResource(stub_id);
        setimageSize(imageView,url);
    }
}

public void displayImage(File file,file.getAbsolutePath());
    Bitmap bitmap=memoryCache.get(file.getAbsolutePath());
    if(bitmap!=null){
        imageView.setimageBitmap(bitmap);
        saveImageSize(imageView,file.getAbsolutePath());
    } 
    else
    {
        queuePhoto(file,file.getAbsolutePath());
    }
}

private void saveImageSize(ImageView imageView,String url){

    int height = imageView.getHeight();
    imagesSizes.put(url,height);
    System.out.println("IMAGE SIZE: Save: " + url + "  " + height );
}

private void setimageSize(ImageView imageView,String url){
    if(imageView != null && imagesSizes!=null && imagesSizes.containsKey(url)){
        imageView.getLayoutParams().height = imagesSizes.get(url);
        imageView.requestLayout();
        System.out.println("IMAGE SIZE: Set: " + url + "  " + imagesSizes.get(url) );
    }
}


private void queuePhoto(String url,ImageView imageView)
{
    PhotoToLoad p=new PhotoToLoad(url,imageView);
    executorService.submit(new Photosloader(p));
}

private void queuePhoto(File file,ImageView imageView)
{
    PhotoToLoad p=new PhotoToLoad(file,imageView);
    executorService.submit(new Photosloader(p));
}

public Bitmap getimage(String url){
    return getBitmap(url);
}

private Bitmap getBitmap(String url) 
{
    File f=fileCache.getFile(url);

    //from SD cache
    Bitmap b = decodeFile(f);
    if(b!=null)
        return b;

    //from web
    try {
        Bitmap bitmap=null;
        URL imageUrl = new URL(url);
        HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
        conn.setConnectTimeout(30000);
        conn.setReadTimeout(30000);
        conn.setInstanceFollowRedirects(true);
        InputStream is=conn.getInputStream();
        OutputStream os = new FileOutputStream(f);
        Utils.copyStream(is,os);
        os.close();
        conn.disconnect();
        bitmap = decodeFile(f);
        return bitmap;
    } catch (Throwable ex){
       ex.printstacktrace();
       if(ex instanceof OutOfMemoryError)
           memoryCache.clear();
       return null;
    }
}

//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
    try {
        //decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        FileInputStream stream1=new FileInputStream(f);
        BitmapFactory.decodeStream(stream1,null,o);
        stream1.close();

        //Find the correct scale value. It should be the power of 2.
        final int required_SIZE=size;
        int width_tmp=o.outWidth,height_tmp=o.outHeight;
        int scale=1;
        while(true){
            if(width_tmp/2<required_SIZE || height_tmp/2<required_SIZE)
                break;
            width_tmp/=2;
            height_tmp/=2;
            scale*=2;
        }

        //decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        FileInputStream stream2=new FileInputStream(f);
        Bitmap bitmap=BitmapFactory.decodeStream(stream2,o2);
        stream2.close();
        return bitmap;
    } catch (FileNotFoundException e) {
    } 
    catch (IOException e) {
        e.printstacktrace();
    }
    return null;
}

//Task for the queue
private class PhotoToLoad
{
    public File file;
    public String url;
    public ImageView imageView;
    public PhotoToLoad(String u,ImageView i){
        url=u; 
        imageView=i;
        file = null;
    }

    public PhotoToLoad(File file,ImageView i){
        url=file.getAbsolutePath(); 
        imageView=i;
        this.file = file;
    }
}

class Photosloader implements Runnable {
    PhotoToLoad photoToLoad;
    Photosloader(PhotoToLoad photoToLoad){
        this.photoToLoad=photoToLoad;
    }

    @Override
    public void run() {
        try{
            if(imageViewReused(photoToLoad))
                return;
            Bitmap bmp;
            if(photoToLoad.file== null){
                bmp=getBitmap(photoToLoad.url);
            } else {
                bmp=decodeFile(photoToLoad.file);
            }
            memoryCache.put(photoToLoad.url,bmp);
            if(imageViewReused(photoToLoad))
                return;
            Bitmapdisplayer bd=new Bitmapdisplayer(bmp,photoToLoad);
            handler.post(bd);
        }catch(Throwable th){
            th.printstacktrace();
        }
    }
}

boolean imageViewReused(PhotoToLoad photoToLoad){
    String tag=imageViews.get(photoToLoad.imageView);
    if(tag==null || !tag.equals(photoToLoad.url))
        return true;
    return false;
}

//Used to display bitmap in the UI thread
class Bitmapdisplayer implements Runnable
{
    Bitmap bitmap;
    PhotoToLoad photoToLoad;
    public Bitmapdisplayer(Bitmap b,PhotoToLoad p){bitmap=b;photoToLoad=p;}
    public void run()
    {
        if(imageViewReused(photoToLoad))
            return;
        if(bitmap!=null)
            photoToLoad.imageView.setimageBitmap(bitmap);
        else
            photoToLoad.imageView.setimageResource(stub_id);
        if(photoToLoad.file== null){
            setimageSize(photoToLoad.imageView,photoToLoad.url);
        } else {
            setimageSize(photoToLoad.imageView,photoToLoad.file.getAbsolutePath());
        }

    }
}



public void clearCache() {
    memoryCache.clear();
    fileCache.clear();
}

编辑:添加适配器:

public class LazyNewPostsAdapter extends BaseAdapter implements Constants{

private Activity activity;
private ArrayList<Image> data;
private static LayoutInflater inflater=null;
private ImageLoader imageLoader; 
private AsyncHelper helper;
public static final int VIEW_TYPE_LOADING = 0;
public static final int VIEW_TYPE_ACTIVITY = 1;

private int imgposition;
Handler fmHandler = null;

Handler handler = new Handler(){
    public void handleMessage(android.os.Message msg) {
        switch(msg.what){
        case HANDLER_NEW_POST_Vote_IMAGE:
                int position = msg.arg1;
            JSONObject json;
            try {
                json = new JSONObject((String) msg.obj);

                int success =  json.getInt("success");

                if(success == 1){

                    int i_id = json.getInt("i_id");
                    int VotesUp = json.getInt("Votes_up");
                    int VotesDown = json.getInt("Votes_down");

                    data.get(position).setVotesUp(VotesUp);
                    data.get(position).setVotesDown(VotesDown);
                    notifyDataSetChanged();
                }

            } catch (JSONException e) {
                e.printstacktrace();
            }   

            break;
        case HANDLER_USER_REPORTED_IMAGE:
            JSONObject json2 = Utils.createJSON((String)msg.obj);
            System.out.println("REPORT IMAGE " + json2);
            if(json2 != null){
                try {
                    int success = json2.getInt("success");
                    if(success==1){
                         Toast.makeText(activity,"Image reported!",Toast.LENGTH_LONG).show();

                    }
                } catch (JSONException e) {
                    // Todo Auto-generated catch block
                    e.printstacktrace();
                }
            }
            break;
        case HANDLER_IMAGE_SIZE_AVAILABLE:
            String url = (String) msg.obj;
            int height = msg.arg1;
            int width = msg.arg2;

            int imgPosition = findImageOfCertainURL(url);
            System.out.println("GETVIEW HANDLER 1: IMAGE POSITION" + imgPosition);

            if(imgPosition != -1){
                data.get(imgPosition).setHeight(height);
                data.get(imgPosition).setWidth(width);
            }
            Message copyMsg = new Message();
            copyMsg.what = HANDLER_IMAGE_SIZE_AVAILABLE;
            copyMsg.arg1 = height;
            copyMsg.arg2 = width;
            copyMsg.obj = url;
            fmHandler.sendMessage(copyMsg);
            notifyDataSetChanged();
            break;
        }
    };
};

private int findImageOfCertainURL(String url){
    for(int i = 0; i <data.size();i++){
        if((URL_FOLDER_IMAGES + data.get(i).getUrl()).equalsIgnoreCase(url)){
            return i;
        }
    }
    return -1;
}

public LazyNewPostsAdapter(Activity a,ArrayList<Image> d,Handler fragmentHandler) {

    activity = a;

    data=d;
    inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    helper =  new AsyncHelper(activity,handler);

    imageLoader=new ImageLoader(activity.getApplicationContext(),600,handler) ;
    fmHandler = fragmentHandler;
}

public void updateData(ArrayList<Image> d){
    data = d;
    notifyDataSetChanged();
}



public int getCount() {
    return data.size()+1;
}

@Override
public int getViewTypeCount() {
    return 2;
}

@Override
public int getItemViewType(int position) {
    // Todo Auto-generated method stub
    return (position >= data.size()) ? VIEW_TYPE_LOADING
            : VIEW_TYPE_ACTIVITY;
}

@Override
public boolean isEnabled(int position) {
    return getItemViewType(position) == VIEW_TYPE_ACTIVITY;
}

public Object getItem(int position) {
    return (getItemViewType(position) == VIEW_TYPE_ACTIVITY) ? data.get(position) : null;
}

public long getItemId(int position) {
    return (getItemViewType(position) == VIEW_TYPE_ACTIVITY) ? position
            : -1;
}

public View getFooterView(int position,View convertView,ViewGroup parent) {

        // the ListView has reached the last row
        TextView tvLastRow = new TextView(activity);
        if(AsyncHelper.isDownloadingImages){
            tvLastRow.setHint("Requesting new Images..");
        } else {

            tvLastRow.setHint("Reached the last row.");
        }
        tvLastRow.setGravity(Gravity.CENTER);
        return tvLastRow;

}

private OnClickListener myHotButtonClickListener = new OnClickListener() {
    @Override
    public void onClick(View v) {
        int position = (Integer) v.getTag();
        if(ActivityMain.user.isLoggedIn()){
            data.get(position).setThisUserVote(1);
            helper.Vote_image(position,data.get(position).getId(),HOT);
        } else {
            Toast.makeText(activity,"Login to Vote",Toast.LENGTH_SHORT).show();
        }
    }
};

private OnClickListener myColdButtonClickListener = new OnClickListener() {
    @Override
    public void onClick(View v) {
        int position = (Integer) v.getTag();
        if(ActivityMain.user.isLoggedIn()){
            data.get(position).setThisUserVote(2);
            helper.Vote_image(position,COLD);
        }else {
            Toast.makeText(activity,Toast.LENGTH_SHORT).show();
        }
    }
};

private OnClickListener myOptionsButtonClickListener = new OnClickListener() {
    @Override
    public void onClick(View v) {
        final int position = (Integer) v.getTag();
        Runnable optionsRunnable = new Runnable() {

            @Override
            public void run() {


                openoptionsDialog(position);

            }
        };
        handler.postDelayed(optionsRunnable,500);


    }
};
private void openoptionsDialog(final int imgposition){
    final CharSequence[] items = {"Share","Save","Report"};

    AlertDialog.Builder builder = new AlertDialog.Builder(activity);
    builder.setTitle("Options");
    builder.setItems(items,new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog,int item) {
            if(item==0){
                Utils.shareImage(activity,imageLoader.getimage(URL_FOLDER_IMAGES + data.get(imgposition).getUrl()),data.get(imgposition).getTitle());
            } else if(item==1) {
                Utils.saveImage(imageLoader.getimage(URL_FOLDER_IMAGES + data.get(imgposition).getUrl()),activity);
            } else if(item==2) {
                openReportDialog(imgposition);
            }
        }
    });
    AlertDialog alert = builder.create();
    alert.show();
}

private void openReportDialog(final int imgposition){

    AlertDialog.Builder builder = new AlertDialog.Builder(activity,R.style.AppCompatAlertDialogStyle);
    builder.setTitle("Report This Image?");
    builder.setPositiveButton("Yes",new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog,int which) {
            helper.reportimage(data.get(imgposition).getId());
        }
    });
    builder.setNegativeButton("No",null);

    AlertDialog alert = builder.create();
    alert.show();
}

public View getView(final int position,ViewGroup parent) {
    if (getItemViewType(position) == VIEW_TYPE_LOADING) {
        // display the last row
        return getFooterView(position,convertView,parent);
    }
    View vi=convertView;
    final ViewHolder holder;
    final Image img = data.get(position);
    boolean isViNull = false;
    if(convertView==null){
    vi = inflater.inflate(R.layout.item_new_posts,null);
        holder = new ViewHolder();
        isViNull = true;
        holder.title=(BrushTextView)vi.findViewById(R.id.tv_newposts_title);
        holder.image=(RatioImageView)vi.findViewById(R.id.iv_newposts_image);
        holder.uploader = (BrushTextView) vi.findViewById(R.id.tv_newposts_uploader);
        holder.upVotes = (BrushTextView) vi.findViewById(R.id.tv_newposts_upVotes);
        holder.downVotes= (BrushTextView) vi.findViewById(R.id.tv_newposts_downVotes);
        holder.options=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_options);

        holder.iv_hot=(ImageView)vi.findViewById(R.id.iv_newposts_button_upVote);
        holder.iv_cold=(ImageView)vi.findViewById(R.id.iv_newposts_button_downVote);
        holder.ll_hot=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_upVote);
        holder.ll_cold=(LinearLayout)vi.findViewById(R.id.ll_newposts_button_downVote);

        vi.setTag(holder);

    } else {
        holder = (ViewHolder) vi.getTag();
    }


    if(img.getHeight() != 0 && img.getWidth() != 0){

        holder.image.getLayoutParams().height = img.getHeight();
        holder.image.getLayoutParams().width = img.getWidth();
        holder.image.requestLayout();
    }
    holder.ll_hot.setTag(position);
    holder.ll_hot.setonClickListener(myHotButtonClickListener);
    holder.ll_cold.setTag(position);
    holder.ll_cold.setonClickListener(myColdButtonClickListener);


    holder.options.setTag(position);
    holder.options.setonClickListener(myOptionsButtonClickListener);


    changeVoteButtonImages(img,holder.iv_hot,holder.iv_cold);
    if(img.getTitle()!=null){
        holder.title.setVisibility(View.VISIBLE);
        holder.title.setText(img.getTitle());
    } else {
        holder.title.setVisibility(View.GONE);
    }
    holder.uploader.setText(img.getUploader());
    holder.upVotes.setText(img.getVotesUp()+"");
    holder.downVotes.setText(img.getVotesDown()+"");
    String url = URL_FOLDER_IMAGES + img.getUrl();
    System.out.println("GETVIEW NEW POST ADAPTER: height = " + img.getHeight() + "  width = " + img.getWidth());
    if(isViNull)
    System.out.println("GETVIEW CONVERTVIEW: VI: "  +vi.getHeight());
    imageLoader.displayImage(url,holder.image);

    return vi;
}

private void changeVoteButtonImages(Image image,ImageView upVote,ImageView  downVote){
    switch(image.getThisUserVote()){
    case 0:
        upVote.setimageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_0));
        downVote.setimageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_0));
        break;
    case 1:
        downVote.setimageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_0));
        upVote.setimageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_1));
        break;
    case 2:
        upVote.setimageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_hot_0));
        downVote.setimageDrawable(activity.getResources().getDrawable(R.drawable.ic_post_cold_1));
        break;
    }
}

static class ViewHolder {            
   public BrushTextView title,uploader,upVotes,downVotes;
   public ImageView iv_hot,iv_cold;
   public LinearLayout options,ll_hot,ll_cold;
   public RatioImageView image; 
}

}

这里是Fragment,它包含ListView

public class Fragment_New_Posts extends Fragment implements Constants,OnRefreshListener{

private static final String ARG_SECTION_NUMBER = "section_number";

private ListView list;
private LazyNewPostsAdapter adapter;
private Images images;
private ArrayList<Image> imagesList;
private SharedPreferences prefs;
private Editor editor;
private int visible_i_id;
private SwipeRefreshLayout swipeLayout;
private int option_image_filter;
private AsyncHelper helper;
private boolean onRefreshFired = false;
private Parcelable state;

public static Fragment_New_Posts newInstance(int sectionNumber) {
    Fragment_New_Posts fragment = new Fragment_New_Posts();
    Bundle args = new Bundle();
    args.putInt(ARG_SECTION_NUMBER,sectionNumber);
    fragment.setArguments(args);
    return fragment;
}

public static Fragment_New_Posts newInstance(int sectionNumber,Images imgs) {
    Fragment_New_Posts fragment = new Fragment_New_Posts(imgs);
    Bundle args = new Bundle();
    args.putInt(ARG_SECTION_NUMBER,sectionNumber);
    fragment.setArguments(args);
    return fragment;
}

public void updateImages(Images images,boolean createNew,boolean loadOldImages){
    int i_id_position = 0;
    this.images = images;
    if(!images.hasErrorOccured){
        if(this.imagesList == null || createNew || onRefreshFired){
            this.imagesList = images.getlistofImages();
        } else {
            this.imagesList.addAll(images.getlistofImages());
        }
    } 

    if(loadOldImages){
        i_id_position = this.images.getIDPosition(visible_i_id);
    }
    if(onRefreshFired){
        swipeLayout.setRefreshing(false);
        onRefreshFired = false;
    }
    synchronized (adapter) {
        adapter.updateData(this.imagesList);
        if(list!=null && createNew){
            if(loadOldImages){
                list.setSelection(i_id_position);
            } else {
                list.setSelection(0);
            }
        }
    }

}

private Handler handler = new Handler(){
    public void handleMessage(android.os.Message msg) {
        switch(msg.what){
        case HANDLER_MAIN_IMAGE_UPDATE:
            String imagesstring =  (String) msg.obj;
            Images imgs = new Images(imagesstring);
            updateImages(imgs,false,false);
            if(imgs.hasErrorOccured){
                Toast.makeText(getActivity(),"Can\'t get new Images",Toast.LENGTH_SHORT).show();
            }
            break;
        case HANDLER_IMAGE_SIZE_AVAILABLE:
            String url = (String) msg.obj;
            int height = msg.arg1;
            int width = msg.arg2;

            int imgPosition = findImageOfCertainURL(url);
            System.out.println("GETVIEW HANDLER 2: IMAGE POSITION" + imgPosition);
            if(imgPosition != -1){
                imagesList.get(imgPosition).setHeight(height);
                imagesList.get(imgPosition).setWidth(width);
            }

            break;
        }

    };
};

private int findImageOfCertainURL(String url){
    for(int i = 0; i <imagesList.size();i++){
        if((URL_FOLDER_IMAGES + imagesList.get(i).getUrl()).equalsIgnoreCase(url)){
            return i;
        }
    }
    return -1;
}

public Fragment_New_Posts() {
}

public Fragment_New_Posts(Images imgs) {
    this.images = imgs;
}

@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
    System.out.println("NEW POST FRAGMENT ONCREATE");
    View rootView = inflater.inflate(R.layout.fragment_new_posts,container,false);
    prefs = getActivity().getSharedPreferences(PREF_WOODU,getActivity().MODE_PRIVATE);
    editor = prefs.edit();
    if(prefs!=null){
        visible_i_id = prefs.getInt(PREF_NEW_POSTS_VISIBLE_I_ID,0);
        option_image_filter = prefs.getInt(PHP_TAG_IMAGE_FILTER,0);
    }
    swipeLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_container);
    swipeLayout.setColorSchemeColors(R.color.red_hot);
    swipeLayout.setonRefreshListener(this);
    helper = new AsyncHelper(getActivity(),handler);
    imagesList = new ArrayList<Image>();
    if(images != null){
        imagesList = images.getlistofImages();
        System.out.println("SAVE IMAGES: load: imgsList " + imagesList);

    }
    list = (ListView) rootView.findViewById(R.id.lv_new_posts);
    adapter = new LazyNewPostsAdapter(getActivity(),imagesList,handler);
    list.setAdapter(adapter);

    list.setonScrollListener(new endlessscrollListener() {
        @Override
        public void onLoadMore(int page,int totalItemsCount) {
            if(imagesList!=null && imagesList.size()!=0){
                helper.getimageUpdate(imagesList.get(imagesList.size()-1).getId(),option_image_filter);
            }
        }
    });

    if(images != null){
        updateImages(images,true,true);
    }

    return rootView;
}



@Override
public void onPause() {
    int lastVisposition = list.getLastVisiblePosition();
    if(lastVisposition>=0 && lastVisposition < this.imagesList.size()){
        visible_i_id = this.imagesList.get(list.getFirstVisiblePosition()).getId();
        editor.putInt(PREF_NEW_POSTS_VISIBLE_I_ID,visible_i_id);
        editor.commit();
    }

    super.onPause();
}




@Override
public void onResume() {
    super.onResume();


}

@Override
public void onDestroy() {
    if(images != null){
        editor.putString(PREF_NEW_POSTS_CURRENT_IMAGES,Utils.createJSONStringFromImageArrayList(imagesList,editor));
        editor.commit();
    }
    super.onDestroy();
}

@Override
public void onRefresh() {
    onRefreshFired = true;
    if(prefs!=null){
        option_image_filter = prefs.getInt(PHP_TAG_IMAGE_FILTER,0);
    }
    helper.getimageUpdate(0,option_image_filter);
}
}

在这里有很多信息和代码.我希望这不会吓到任何人提供帮助:D

谢谢!!

解决方法

请,请,请不要“重新发明轮子”并使用任何lib来进行图像加载,缓存等,如Picasso,Fresco,Glide等….

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇“android轻量级无侵入式管理数据库自动升级组件怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定...
今天小编给大家分享一下Android实现自定义圆形进度条的常用方法有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文...
这篇文章主要讲解了“Android如何解决字符对齐问题”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android...
这篇文章主要介绍“Android岛屿数量算法怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Android岛屿数量算...
本篇内容主要讲解“Android如何开发MQTT协议的模型及通信”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Andro...
本文小编为大家详细介绍“Android数据压缩的方法是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android数据压缩的方法是什么”文章能帮助大家解决疑惑...
这篇“Android怎么使用Intent传大数据”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅...
本文小编为大家详细介绍“Android事件冲突怎么解决悬浮窗拖拽问题”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android事件冲突怎么解决悬浮窗拖拽问题”文...
这篇文章主要介绍了Android拼接如何实现动态对象的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android拼接如何实现动态对象文...
今天小编给大家分享一下Android全面屏适配怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下...
本篇内容介绍了“Android怎么开发Input系统触摸事件分发”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何...
今天小编给大家分享一下AndroidRoom怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下...
本文小编为大家详细介绍“AndroidRoom使用方法有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“AndroidRoom使用方法有哪些”文章能帮助大家...
这篇文章主要介绍“Android中的OpenGL怎么配置使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Android中的Open...
这篇文章主要介绍了Android如何自定义自动识别涂鸦工具类的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android如何自定义自动...
今天小编给大家分享一下Android如何自定义有限制区域的图例角度自识别涂鸦工具类的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以...
今天小编给大家分享一下ReactNative错误采集原理在Android中如何实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章...
这篇文章主要讲解了“Android崩溃日志收集和保存代码分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“A...
这篇“Android面向单Activity开发实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大...
本篇内容介绍了“Android应用启动白屏处理的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何...