Android高徳地図開発(四)カスタムオフライン地図ダウンロード

25647 ワード

一、概説
前の章では、POIデータ、バスデータ、天気データなど、高徳地図の操作について基本的な理解を持っています.これらはすべて高徳地図が私たちのためにAPIを設計してくれたので、呼び出すだけでいいです.しかし、この章では、折りたたみリストをカスタマイズし、対応する都市地図をダウンロードする方法について説明します.鴻洋大神が提供した折りたたみリストの考え方に感謝します.
二、本章の内容
---オフラインマップをダウンロード---リスト1を折りたたむ.まず、都市データを取得する必要があります.また、高徳地図APIのOfflineMapManagerクラスは、主にオフラインマップのダウンロード、データの取得などの機能を管理するために使用されます.OfflineMapManager(Context ctx, OfflineMapManager.OfflineMapDownloadListener listener); OfflineMapManagerのコンストラクション関数から、最初のパラメータはコンテキストであり、2番目のパラメータはダウンロードマップを傍受するインタフェースであることがわかります.このインタフェースを実現するには3つの方法が必要です
    @Override
    public void onDownload(int i, int i1, String s) {
        //             
    }

    @Override
    public void onCheckUpdate(boolean b, String s) {
        //             
    }

    @Override
    public void onRemove(boolean b, String s, String s1) {
        //             
    }

メソッド名から大まかな役割がわかりますが、ここでは多くの説明にすぎません.OfflineMapManagerの例があれば、次は高徳地図の都市データを取得します.
//                //      
//                OfflineMapManager.getOfflineMapCityList()
//                //      
//                OfflineMapManager.getOfflineMapProvinceList()
//                //          
//                OfflineMapManager.getDownloadOfflineMapCityList()
//                //           
//                OfflineMapManager.getDownloadingCityList()

2.折りたたみリスト実装、データがあれば次に折りたたみリストを開始します.ここではRecyclerViewを使用して実装しますが、まだListViewを使用している学生はRecyclerViewを使用してください.強くお勧めします(RecyclerViewの強さは誰が知っていますか).まず原理を説明します:私たちが実現しなければならない効果は以下の通りです.
    /**
     *       1-------      
     *       2-------     
     *          2.1-------      
     *          2.2-------      
     *          2.3-------     
     *              2.3.1---      
     *              2.3.2---      
     *       3-------      
     * */

もし私たちがこの3級の折りたたみしかなければ、1,2,3はルートノードです.2.1,2.2,2.3はルートノード2のサブノードである.同理2.3.1,2.3.2は二次ノードの2.3ノードのサブノードである.ではAndroidのリストコントロール表示では、見える部分しか表示されないので、Adapterには2つのデータセットが必要です.
1つ目はすべてのノードのすべてのデータセットであり、2つ目は私たちが示す必要があるデータセットです.展開可能なノードをクリックすると、表示データセットの内容を再リフレッシュしてリストに表示します.これによりデータ表示の問題が解決され,もう一つの難題はデータ格納の順序である.
Androidのリストが上から下へ表示されていることを知っていますが、折りたたみリストではどのようにデータのソートを行いますか?子ノードには親ノードを保存する必要があり、親ノードにもすべての子ノードのセットが必要です.例:
    /**
     *  new Node(1, 0, "  ")
     *  new Node(2, 1, "Java      ")
     *  new Node(3, 1, "Mysql      ")
     *  new Node(4, 1, "Mysql      ")
     *  new Node(5, 1, "Android      ")
     *  new Node(6, 1, "PHP")
     *  new Node(7, 0, "  ")
     *  new Node(8, 0, "  ")
     *  new Node(9, 8, "    ")
     *  new Node(10, 8, "    ")
     *  new Node(11, 8, "    ")
     *  new Node(12, 8, "    ")
     *  new Node(13, 0, "  ")
     *  new Node(14, 13, "       ")
     *  new Node(15, 14, "Java")
     *  new Node(16, 14, "C++")
     *  new Node(17, 14, "JavaScript")
     *  new Node(18, 14, "PHP")
     *  new Node(19, 13, "       ")
     *  new Node(20, 19, "C")
     *
     * */

Nodeクラス構築方法1番目のパラメータがシーケンス番号、2番目のパラメータが親ノードシーケンス番号、3番目のパラメータがそのノードの内容であり、上記のインスタンスを順番にデータセットに追加すると、データは完了します.
上の段落はただ原理を簡明にするために例を挙げただけで、私たちはここでオフラインの地図をダウンロードするのはやはり違いますが、原理はすべてこのようにして、理論的にはこれは多くの段の折り畳みを実現することができますが、私は3段の折り畳みがもう十分で、さらに上へあなたがデータを処理する時もっと複雑になることをお勧めします.
原理がわかったら直接コードをつけます.Activity
public class OfflineMapActivity extends BaseActivity implements OfflineMapManager.OfflineMapDownloadListener {


    @BindView(R.id.m_recycler_view)
    RecyclerView mRecyclerView;
    private Unbinder binder;

    //        
    private OfflineMapManager omm;
    //  list
    private ArrayList provinces;

    private TreeAdapter mAdapter;

    @Override
    public void setContentView(@Nullable Bundle savedInstanceState) {
        setContentView(R.layout.activity_offline_map);
        binder = ButterKnife.bind(this);
    }

    @Override
    public void initData() {

        provinces = new ArrayList<>();
        omm = new OfflineMapManager(this, this);
        mAdapter = new TreeAdapter(getApplicationContext());
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        mRecyclerView.addItemDecoration(new LinearLayoutDecoration(this, LinearLayoutManager.VERTICAL));
        mRecyclerView.setAdapter(mAdapter);

        ArrayList data = omm.getOfflineMapProvinceList();
        
        //          ,    run()           
        MyApplication.getInstance().getPoolExecutor().execute(new Runnable() {
            @Override
            public void run() {

                String path = Environment.getExternalStorageDirectory() + "/MyMap/maps";
                File file = new File(path);
                if (!file.exists()) {
                    file.mkdirs();
                }

                //             
                MapsInitializer.sdcardDir = path;

//                //      
//                OfflineMapManager.getOfflineMapCityList()
//                //      
//                OfflineMapManager.getOfflineMapProvinceList()
//                //          
//                OfflineMapManager.getDownloadOfflineMapCityList()
//                //           
//                OfflineMapManager.getDownloadingCityList()

                //          
                ArrayList data = omm.getOfflineMapProvinceList();
                provinces = getProvinceData(data);
                //                     

                //       ,   pid = 0,
                final ArrayList allNodes = new ArrayList<>();
                int index = 0;
                for (int i = 0; i < provinces.size(); i++) {

                    Node n = new Node(index, 0);
                    n.setParentNode(null);
                    n.setData(provinces.get(i));
                    n.setExpand(false);
                    n.setLevel(1);

                    ArrayList subNodes = n.getSubNodeList();
                    n.setSubNodeList(subNodes);

                    ArrayList cities = provinces.get(i).getCitys();
                    for (int j = 0; j < cities.size(); j++) {
                        index++;

                        Node one = new Node(index, n.getId());
                        one.setParentNode(n);
                        one.setData(cities.get(j));

                        one.setParentNode(n);
                        one.setLevel(2);
                        one.setExpand(false);
                        subNodes.add(one);
                    }

                    allNodes.add(n);
                    index++;
                }

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mAdapter.setData(allNodes);
                    }
                });
            }
        });

        mAdapter.setListener(new TreeAdapter.OnClickListener() {
            @Override
            public void onClick(int position, String cityCode) {
                try {

                    omm.downloadByCityCode(cityCode);
                    mAdapter.setStartDownLoading(position);
                } catch (AMapException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void pause() {
                if (omm != null) {
                    omm.pause();
                }
            }
        });
    }

    /**
     *     ,           
     */
    private ArrayList getProvinceData(ArrayList data) {

        ArrayList result = new ArrayList<>();
        //      ,      
        for (int i = 0; i < data.size(); i++) {

            ArrayList cityList = new ArrayList<>();
            Province p = new Province();
            p.setName(data.get(i).getProvinceName())
                    .setSimplicity(data.get(i).getJianpin())
                    .setFullPinyin(data.get(i).getPinyin())
                    .setProvinceCode(data.get(i).getProvinceCode())
                    .setCitys(cityList);

            ArrayList cities = data.get(i).getCityList();
            //          ,              
//                    if (cities != null && cities.size() > 0) {
            for (int j = 0; j < cities.size(); j++) {

                City c = new City();
                c.setName(cities.get(j).getCity())
                        .setSimplicity(cities.get(j).getJianpin())
                        .setFullPinyin(cities.get(j).getPinyin())
                        .setCityCode(cities.get(j).getCode())
                        .setProvinceCityCode(cities.get(j).getAdcode());

                cityList.add(c);
            }
//                    }
            result.add(p);
        }
        return result;
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {

        //  binder   super.onDestroy()   ,       ,   UI         ,    
        binder.unbind();
        super.onDestroy();
    }

    @Override
    public void onDownload(int i, int i1, String s) {
        //             
        // i -------   
        // i1 -------     
        // s -------     
        Log.e("CF", "onDownload: i=" + i + " i1=" + i1 + " s=" + s);
        if (i == 0) {
            //    
            mAdapter.setDownloading(i1, s);
        } else if (i == -1) {
            //    
            mAdapter.downloadComplete(s);
        }
    }

    @Override
    public void onCheckUpdate(boolean b, String s) {
        //             
        Log.e("CF", "onCheckUpdate: b=" + b + " s=" + s);
    }

    @Override
    public void onRemove(boolean b, String s, String s1) {
        //             
        Log.e("CF", "onRemove: b=" + b + " s=" + s + " s1=" + s1);
    }

}

Adapter
public class TreeAdapter extends RecyclerView.Adapter {

    //item    
    private final static int NODE = 0;
    private final static int LEAF = 1;
    //    
    private ArrayList allNodes;
    //    
    private ArrayList visibleNodes;

    private LayoutInflater lf; //    
    private Context context;
    //    
    private OnClickListener listener;

    public TreeAdapter(Context context) {
        this.context = context.getApplicationContext();

        lf = LayoutInflater.from(this.context);

        visibleNodes = new ArrayList<>();
    }

    /**
     *       
     * */
    private void filterVisibleNode() {

        visibleNodes.clear();

        for (int i = 0; i < allNodes.size(); i++) {

            Node one = allNodes.get(i);
            if (one.getPid() == 0 && !one.isSubNode()) {
                visibleNodes.add(one);
                expandNode(one);

            } else if (one.getPid() == 0 && one.isSubNode()) {
                visibleNodes.add(one);
            }
        }
    }

    /**
     *           ,          ,    
     *   : 1-------
     *       2-------
     *          2.1-------
     *          2.2-------
     *          2.3-------
     *              2.3.1---
     *              2.3.2---
     *       3-------
     *
     *                 visibleNodes 
     * */
    private void expandNode(Node one) {
        //         ,     
        if (one.isExpand() && !one.isSubNode()) {

            ArrayList subLists = one.getSubNodeList();
            for (int j = 0; j < subLists.size(); j++) {
                visibleNodes.add(subLists.get(j));
                expandNode(subLists.get(j));
            }
        }
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        //              Item  
        if (viewType == NODE) {

            NodeViewHolder holder = new NodeViewHolder(lf.inflate(R.layout.item_ndoe_layout, parent, false));
            return holder;

        } else if (viewType == LEAF) {

            LeafViewHolder holder = new LeafViewHolder(lf.inflate(R.layout.item_leaf_layout, parent, false));
            return holder;
        }
        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {

        if (holder instanceof NodeViewHolder) {

            //      item  
            if (visibleNodes.get(position).isExpand()) {
                ((NodeViewHolder) holder).itemImag.setImageResource(R.drawable.triangle_bottom);
            } else {
                ((NodeViewHolder) holder).itemImag.setImageResource(R.drawable.triangle_right);
            }
            ((NodeViewHolder) holder).itemLayout.setPadding(visibleNodes.get(position).getLevel() * 30, 5, 5, 5);

            final Province p = (Province) visibleNodes.get(position).getData();
            ((NodeViewHolder) holder).itemText.setText(p.getName());

            ((NodeViewHolder) holder).itemLayout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    int id = visibleNodes.get(position).getId();
                    for (int i = 0; i < allNodes.size(); i++) {
                        if (allNodes.get(i).getId() == id) {

                            if (allNodes.get(i).isExpand()) {
                                allNodes.get(i).setExpand(false);
                            } else {
                                allNodes.get(i).setExpand(true);
                            }
                            break;
                        }
                    }
                    filterVisibleNode();
                    notifyDataSetChanged();
                }
            });

        } else if (holder instanceof LeafViewHolder) {

            //    ,           item  
            final City c = (City) visibleNodes.get(position).getData();

            ((LeafViewHolder) holder).itemText.setText(c.getName());
            ((LeafViewHolder) holder).itemLayout.setPadding(20 + visibleNodes.get(position).getLevel() * 20, 5, 5, 0);
            ((LeafViewHolder) holder).itemLeafDownBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        if (!visibleNodes.get(position).isLoading()) {

                            listener.onClick(position, c.getCityCode());
                            visibleNodes.get(position).setLoading(true);
                        } else {
                            listener.pause();
                            visibleNodes.get(position).setLoading(false);
                        }
                        notifyDataSetChanged();
                    }
                }
            });

            if (visibleNodes.get(position).isLoading()) {
                ((LeafViewHolder) holder).itemLeafDownBtn.setBackgroundResource(R.drawable.pause);
            } else {
                ((LeafViewHolder) holder).itemLeafDownBtn.setBackgroundResource(R.drawable.dwonload);
            }


            if (visibleNodes.get(position).isVisible()) {
                ((LeafViewHolder) holder).itemLeafDownloadingLayout.setVisibility(View.VISIBLE);
                ((LeafViewHolder) holder).itemLeafPercentText.setText(visibleNodes.get(position).getPercent() + "%");
                ((LeafViewHolder) holder).itemLeafProgressbar.setProgress(visibleNodes.get(position).getPercent());
            } else {
                ((LeafViewHolder) holder).itemLeafDownloadingLayout.setVisibility(View.GONE);
            }

            if (visibleNodes.get(position).isDowned()) {
                ((LeafViewHolder) holder).itemLeafDownBtn.setVisibility(View.INVISIBLE);
                ((LeafViewHolder) holder).itemLeafDownText.setVisibility(View.VISIBLE);
            } else {
                ((LeafViewHolder) holder).itemLeafDownBtn.setVisibility(View.VISIBLE);
                ((LeafViewHolder) holder).itemLeafDownText.setVisibility(View.INVISIBLE);
            }
        }

    }

    @Override
    public int getItemCount() {
        return visibleNodes == null ? 0 : visibleNodes.size();
    }

    @Override
    public int getItemViewType(int position) {
        if (visibleNodes.get(position).isSubNode()) {
            return LEAF;
        } else {
            return NODE;
        }
    }

    /**
     *       
     * */
    public void setData(ArrayList allNodes) {
        this.allNodes = allNodes;

        filterVisibleNode();

        notifyDataSetChanged();
    }

    /**
     *       
     * */
    public void setDownloading(int percent, String cityName) {

        for (Node one : visibleNodes) {
            if (one.isSubNode()) {
                City c = (City) one.getData();
                if (c.getName().equals(cityName)) {
                    one.setPercent(percent);
                    one.setVisible(true);
                    break;
                }
            }
        }

        notifyDataSetChanged();
    }

    /**
     *     
     * */
    public void downloadComplete(String cityName) {

        for (Node one : visibleNodes) {
            if (one.isSubNode()) {

                City c = (City) one.getData();
                if (c.getName().equals(cityName)) {
                    one.setVisible(false);
                    one.setDowned(true);
                    break;
                }
            }
        }
        notifyDataSetChanged();
    }

    /**
     *       
     * */
    public void setStartDownLoading(int position) {

        visibleNodes.get(position).setVisible(true);
        notifyDataSetChanged();
    }

    public class NodeViewHolder extends RecyclerView.ViewHolder {

        private LinearLayout itemLayout;
        private ImageView itemImag;
        private TextView itemText;

        public NodeViewHolder(View itemView) {
            super(itemView);

            itemLayout = itemView.findViewById(R.id.item_node_layout);
            itemImag = itemView.findViewById(R.id.item_node_img);
            itemText = itemView.findViewById(R.id.item_node_content);
        }
    }

    public class LeafViewHolder extends RecyclerView.ViewHolder {

        private ConstraintLayout itemLayout;
        private TextView itemText;
        private TextView itemLeafPercentText;
        private ProgressBar itemLeafProgressbar;
        private RelativeLayout itemLeafDownloadingLayout;

        private ImageView itemLeafDownBtn;
        private TextView itemLeafDownText;

        public LeafViewHolder(View itemView) {
            super(itemView);
            itemLayout = itemView.findViewById(R.id.item_leaf_layout);
            itemText = itemView.findViewById(R.id.item_leaf_content);
            itemLeafPercentText = (TextView) itemView.findViewById(R.id.item_leaf_percent_text);
            itemLeafProgressbar = (ProgressBar) itemView.findViewById(R.id.item_leaf_progressbar);
            itemLeafDownloadingLayout = (RelativeLayout) itemView.findViewById(R.id.item_leaf_downloading_layout);
            itemLeafDownBtn = (ImageView) itemView.findViewById(R.id.item_leaf_down_btn);
            itemLeafDownText = (TextView) itemView.findViewById(R.id.item_leaf_down_text);
        }
    }

    public void setListener(OnClickListener listener) {
        this.listener = listener;
    }

    public interface OnClickListener {
        void onClick(int position, String cityCode);

        void pause();
    }
}

データカプセル化クラス
public class City {

    //    
    private String name;
    //    
    private String cityCode;
    //  
    private String simplicity;
    //  
    private String fullPinyin;
    //        , :       
    private String provinceCityCode;

    public City() {
        this.name = "";
        this.cityCode = "";
        this.simplicity = "";
        this.fullPinyin = "";
        this.provinceCityCode = "";
    }

    public String getName() {
        return name;
    }

    public City setName(String name) {
        this.name = name;
        return this;
    }

    public String getCityCode() {
        return cityCode;
    }

    public City setCityCode(String cityCode) {
        this.cityCode = cityCode;
        return this;
    }

    public String getSimplicity() {
        return simplicity;
    }

    public City setSimplicity(String simplicity) {
        this.simplicity = simplicity;
        return this;
    }

    public String getFullPinyin() {
        return fullPinyin;
    }

    public City setFullPinyin(String fullPinyin) {
        this.fullPinyin = fullPinyin;
        return this;
    }

    public String getProvinceCityCode() {
        return provinceCityCode;
    }

    public City setProvinceCityCode(String provinceCityCode) {
        this.provinceCityCode = provinceCityCode;
        return this;
    }
}


public class Province {

    //    
    private String name;
    //  
    private String simplicity;
    //  
    private String fullPinyin;
    //    
    private String provinceCode;
    //      
    private ArrayList citys;

    public Province() {
        this.name = "";
        this.simplicity = "";
        this.fullPinyin = "";
        this.provinceCode = "";
        this.citys = new ArrayList<>();
    }

    public String getName() {
        return name;
    }

    public Province setName(String name) {
        this.name = name;
        return this;
    }

    public String getSimplicity() {
        return simplicity;
    }

    public Province setSimplicity(String simplicity) {
        this.simplicity = simplicity;
        return this;
    }

    public String getFullPinyin() {
        return fullPinyin;
    }

    public Province setFullPinyin(String fullPinyin) {
        this.fullPinyin = fullPinyin;
        return this;
    }

    public String getProvinceCode() {
        return provinceCode;
    }

    public Province setProvinceCode(String provinceCode) {
        this.provinceCode = provinceCode;
        return this;
    }

    public ArrayList getCitys() {
        return citys;
    }

    public Province setCitys(ArrayList citys) {
        this.citys = citys;
        return this;
    }
}

public class Node {

    //  id
    private int id;
    // id
    private int pid;
    //  
    private int level;
    //  ,       item   ,    ,            ,      
    private Object data;
    //     
    private Node parentNode;
    //     
    private ArrayList subNodeList;
    //    
    private boolean isExpand;

    //-------------------------------           ,      ,                -----------------------------------------
    //   
    private int percent;
    //       
    private boolean isVisible;
    //    
    private boolean isLoading;
    //      
    private boolean isDowned;

    public Node(int id, int pid) {
        this.id = id;
        this.pid = pid;
        this.parentNode = null;
        this.data = null;
        this.subNodeList = new ArrayList<>();
        this.isExpand = false;
        this.percent = 0;
        this.isVisible = false;
        this.isLoading = false;
        this.isDowned = false;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Node getParentNode() {
        return parentNode;
    }

    public void setParentNode(Node parentNode) {
        this.parentNode = parentNode;
    }

    public ArrayList getSubNodeList() {
        return subNodeList;
    }

    public void setSubNodeList(ArrayList subNodeList) {
        this.subNodeList = subNodeList;
    }

    public boolean isSubNode() {
        return subNodeList.size() == 0;
    }

    public boolean isExpand() {
        return isExpand;
    }

    public void setExpand(boolean expand) {
        isExpand = expand;
    }

    public int getPercent() {
        return percent;
    }

    public void setPercent(int percent) {
        this.percent = percent;
    }

    public boolean isVisible() {
        return isVisible;
    }

    public void setVisible(boolean visible) {
        isVisible = visible;
    }

    public boolean isLoading() {
        return isLoading;
    }

    public void setLoading(boolean loading) {
        isLoading = loading;
    }

    public boolean isDowned() {
        return isDowned;
    }

    public void setDowned(boolean downed) {
        isDowned = downed;
    }
}