項目需求討論-RecycleView分頁加載實現(xiàn)分析

我已經(jīng)寫了個Demo上傳到GitHub上了。大家可以看看。BaseLoadAdapter

大家好,又是新的一期項目需求討論,這期的需求是關(guān)于分頁加載。我本來先是網(wǎng)上看RecycleView的分頁加載的方式,但是看到很多文章都是幫你封裝好,然后讓你拿來直接用,一是直接拿別人封裝的東西自己還是不理解,二是如果要加定制化的東西,改別人的代碼畢竟不方便,或者你就用了一個功能,別人封裝好的可能包含很多功能,就多余了。所以我主要還是來分析,分頁加載到底是怎么樣一步步來實現(xiàn),而不是說封裝好來讓大家使用。

什么是分頁加載,通俗的說就是,比如你在微信朋友圈,可能今天一共有100個別人發(fā)在朋友圈的狀態(tài):
有二種方式加載方式:

  1. 后臺是直接把100個別人發(fā)的狀態(tài)一次性給你了,然后你在列表上層顯示100個朋友圈狀態(tài),然后上下滑動查看。
  2. 可能后臺先給你10個朋友圈狀態(tài),然后當(dāng)你拉到底的時候,顯示<加載中>,然后再去像后臺請求后面10條朋友圈狀態(tài),然后再滑到底部,再去加載10個新的數(shù)據(jù)。一直到最后100個數(shù)據(jù)都加載完了。就在底部顯示<沒有更多數(shù)據(jù)>了。用戶也就知道今天朋友圈狀態(tài)已經(jīng)看完了。

優(yōu)缺點
第一種加載開發(fā)起來方便,簡單。可以直接下滑看全部狀態(tài),不需要看幾條,等它加載更多后,再看幾條,再等著加載再去看。但是如果你只看了前面5個朋友圈狀態(tài),卻把100條的數(shù)據(jù)都發(fā)給你,一個是流量問題,一個是加載的速度問題。畢竟數(shù)據(jù)變多了,而且萬一有好幾千條數(shù)據(jù)怎么辦。

第二種開發(fā)起來麻煩,要設(shè)置多種狀態(tài)。比如滑到底了要去再去獲取信息,然后顯示<加載中>,如果還有數(shù)據(jù)就加入,沒有數(shù)據(jù)再去顯示<沒用更多數(shù)據(jù)>。然后假如獲取失敗,還要顯示<加載失敗>。但是彌補了上述的第一種方法的缺點

所以第一種更適合用于條數(shù)固定,或者條數(shù)不多的情況下。開發(fā)方便。比如微信的聯(lián)系人列表。一般都是直接全部層顯,不會說我先顯示幾個聯(lián)系人,然后下拉再加載再去加載剩下的聯(lián)系人。第二種更適合數(shù)據(jù)會不停的變多的情況,比如你的某個軟件有個交易查詢功能,查詢你的交易記錄,雖然剛開始你的列表上的數(shù)據(jù)比較少,但是隨著時間的推移,你的數(shù)據(jù)也會越來越多。所以就更適合第二種方式。


好了我們開始我們的正題,也正是項目中遇到的具體需求。

后臺接口:

現(xiàn)在是一個交易記錄列表,后臺給我的接口是這樣的:第一次給我10個數(shù)據(jù),我這邊就先顯示10個,然后上拉到底的時候,把最后一個數(shù)據(jù)的orderid(也就是訂單id)給他,他再根據(jù)這個id,加載接下來這個訂單后面的10個數(shù)據(jù)給我。
(以前還有一種接口是這樣的。比如第一次要數(shù)據(jù)的時候給我10條,然后同時給我一個頁數(shù)的字段,告訴我如果是一頁10條的話,一共有幾頁,然后我后面再去加載數(shù)據(jù)的時候就傳頁數(shù)即可。)

(以下為了方便。我都假設(shè)每次后臺最多傳遞給我4個數(shù)據(jù)。)

第一步:

第一次調(diào)用接口拿數(shù)據(jù),分二種情況:

  1. 第一次給我就沒有4條數(shù)據(jù),比如就給我3條,那就說明肯定沒有其他數(shù)據(jù)了。這時候你就算拉到最下面,也不需要顯示什么加載更多的顯示。(別問我為啥。因為如果還有更多,最少也要給你4條)
  1. 如果給了你4條,這時候你滑到底部就要顯示<加載中>。因為有可能說明后面還有數(shù)據(jù)。
    那我們怎么樣才能滑到下面的時候能看到<加載中>這個呢,其實很簡單,把這個<加載中>也作為RecycleView的列表中的一項即可。
    如下圖所示:

這樣是不是當(dāng)你滑到最下面的時候一定能看到<加載中>這一項了。

所以在第一次訪問的時候,我們的RecycleView的adapter中返回列表的個數(shù)要進(jìn)行判斷。如果是小于4條(就是跟后臺約定好的條數(shù)),那adapter中item的個數(shù)直接返回就是實際的條數(shù),比如返回三條,那我們列表就只要顯示3條即可。如果是返回了4條,那么我們這時候adapter中item的個數(shù)就返回4+1 條了。(4條數(shù)據(jù)外加一個<加載中>這一項)。

第二步:

我們既然我們知道我們需要有<加載中>這一項,那我們就肯定知道這個<加載中>跟我們上面的具體的一項項數(shù)據(jù)的布局肯定不一樣。比如我上面實際開發(fā)中,上面的數(shù)據(jù)布局是交易記錄。那我們就來看怎么實現(xiàn)這個RecycleView的列表中如何層顯不同布局。
我們自定義一個BaseLoadAdapter繼承RecycleView.Adapter。然后覆寫public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)方法。
這里面有個viewType,我們可以根據(jù)不同的viewType來返回不同的ViewHolder即可。那這個viewType又是怎么來的。就是復(fù)寫
public int getItemViewType(int position)方法,不同的position
的item,返回特定的viewType即可。

所以我們這里就是:

public class BaseLoadAdapter<T> extends RecyclerView.Adapter {

    public List<T> list;
    public static final int TYPE_OTHER = 1;
    public static final int TYPE_BOTTOM = 2;

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

        if (TYPE_BOTTOM == viewType) {
            //返回我們的那個加載中的布局Viewholder
            return new NewBottomViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_footer_new, parent, false));
        } else {
            //返回我們的交易記錄的布局Viewholder
            return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_transferexam_info, parent, false));
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (getItemViewType(position) == TYPE_BOTTOM) {
            //對相應(yīng)的onBindViewHolder進(jìn)行處理
            LinearLayout container = ((BaseLoadMoreAdapter.NewBottomViewHolder) holder).container;
            final ProgressBar pb = ((BaseLoadMoreAdapter.NewBottomViewHolder) holder).pb;
            final TextView content = ((BaseLoadMoreAdapter.NewBottomViewHolder) holder).content;

            .................
            .................
            .................
        } else {
            //對具體的交易記錄的itemView進(jìn)行相應(yīng)的控件進(jìn)行處理。
            TransferExamItemBean bean = ((TransferExamItemBean) list.get(position));
            holder.itemView.setTag(bean);
            ((ExamRefreshAdapter.MyViewHolder) holder).name.setText(bean.getToCompanyName());
            ((ExamRefreshAdapter.MyViewHolder) holder).date.setText(bean.getCreateDate());
            ((ExamRefreshAdapter.MyViewHolder) holder).money.setText(bean.getAmount()+"");
        }
    }

    @Override
    public int getItemCount() {
        return list.size() < 4 ? list.size() : list.size() + 1;
    }

    @Override
    public int getItemViewType(int position) {
        if (!list.isEmpty() && list.size() < position ) {
            return TYPE_OTHER;
        } else {
            return TYPE_BOTTOM;
        }
    }
}

第三步:

好了,現(xiàn)在我們已經(jīng)可以滑到下面的時候能看到<加載中>這一項了。因為我們看到<加載中>的時候要繼續(xù)去向后臺訪問獲取數(shù)據(jù),說明當(dāng)滑到底部看到這個<加載中>的時候我們就要去調(diào)用相應(yīng)的后臺接口去獲取接下來的交易記錄數(shù)據(jù)。那問題就變成了:我們怎么知道我們已經(jīng)滑到了底部并且已經(jīng)出現(xiàn)了<加載中>這一項,然后進(jìn)行網(wǎng)絡(luò)接口調(diào)用。

自定義繼承RecyclerView.OnScrollListener,復(fù)寫public void onScrolled(RecyclerView recyclerView, int dx, int dy)方法,我們就可以監(jiān)聽RecycleView的滑動了。

public class LoadMoreScrollListener etends RecyclerView.OnScrollListener {

    private RecyclerView mRecyclerView;

    public LoadMoreScrollListener(RecyclerView recyclerView) {
        this.mRecyclerView = recyclerView;
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        RecyclerView.LayoutManager manager = mRecyclerView.getLayoutManager();
        BaseLoadMoreAdapter adapter = (BaseLoadMoreAdapter) mRecyclerView.getAdapter();

        if (null == manager) {
            throw new RuntimeException("you should call setLayoutManager() first!!");
        }
        if (manager instanceof LinearLayoutManager) {
            int lastCompletelyVisibleItemPosition = ((LinearLayoutManager) manager).findLastCompletelyVisibleItemPosition();
           
            if (adapter.getItemCount() > 4 &&
                    lastCompletelyVisibleItemPosition == adapter.getItemCount() - 1 &&
                    adapter.isHasMore()) {
                    
                adapter.isLoadingMore();

            }
        }
    }
}

說明:

  • adapter.getItemCount():獲取adapter一共有多少項。
  • findLastCompletelyVisibleItemPosition():由字面意思就可以看懂,返回最后一個完全可見的item項的position值。因為position是從0開始的,所以當(dāng)findLastCompletelyVisibleItemPosition()返回的是adapter.getItemCount() - 1的時候,就說明已經(jīng)可以看到最后一項了。
  • adapter.isHasMore():這個方法是我們自己在adapter中自定義的方法,返回一個boolean值,比如我們再次調(diào)用后臺接口獲取數(shù)據(jù)的時候,后臺給我們返回的數(shù)據(jù)已經(jīng)為空了。那我們就知道我們后面已經(jīng)無法加載更多數(shù)據(jù)了。這時候把這個boolean值設(shè)為false,這樣在監(jiān)聽滑動的時候就算滑到最底下也不需要去再次調(diào)用接口。
  • adapter.isLoadingMore():這個方法也是我們自己在adapter中自定義的方法,去調(diào)用后臺接口。獲取數(shù)據(jù)等后續(xù)操作。

然后進(jìn)行監(jiān)聽即可recyclerView.addOnScrollListener(new LoadMoreScrollListener(recyclerView));

第四步:

底部這個<加載中>item在以后會有二種狀態(tài),一種是<加載失敗>選項,一種是后臺給的數(shù)據(jù)為空后的<沒有更多>選項。
而我們第一次滑到底部的時候,總是先顯示<加載中>。
因為這個最后一個選項會有三種狀態(tài)顯示情況。(即:<加載中>,<加載失敗>,<加載更多>)所以定義一個變量。用來記錄最后一項當(dāng)前的狀態(tài)。

public int loadState;
int STATE_LOADING = 1;
int STATE_LASTED = 2;
int STATE_ERROR = 3;

因為我們在滑到底部的時候去調(diào)用我們自己定義在adapter中的自定義方法isLoadingMore(),這個方法里面是什么內(nèi)容呢:

public final void isLoadingMore() {
        if (loadState == STATE_LOADING) {
            return;
        }
        loadState = STATE_LOADING;
        notifyItemRangeChanged(getItemRealCount(), 1);
}

沒錯,我們就是默認(rèn)先讓當(dāng)前最后一項的狀態(tài)先變?yōu)镾TATE_LOADING,然后去刷新最后一項的內(nèi)容,notifyItemRangeChanged(int positionStart, int itemCount)方法,從字面意思就能看出通知某個范圍內(nèi)的數(shù)據(jù)發(fā)生改變了。從posistionStart開始的itemCount個數(shù)據(jù)發(fā)生變化。我們因為是最后一項,它的position是list.size(),然后個數(shù)是一個,所以是notifyItemRangeChanged(getItemRealCount(), 1);

然后在通知最后一項發(fā)生變化后我們的onBindViewHolder就會再次被調(diào)用,這時候我們就要根據(jù)相應(yīng)的不同STATE狀況下對這個最后一項的布局進(jìn)行相應(yīng)的處理:

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (getItemViewType(position) == TYPE_BOTTOM) {
            //對相應(yīng)的onBindViewHolder進(jìn)行處理
            LinearLayout container = ((BaseLoadMoreAdapter.NewBottomViewHolder) holder).container;
            final ProgressBar pb = ((BaseLoadMoreAdapter.NewBottomViewHolder) holder).pb;
            final TextView content = ((BaseLoadMoreAdapter.NewBottomViewHolder) holder).content;
          

           //根據(jù)不同state來進(jìn)行相應(yīng)處理
            switch (loadState) {
                //1.當(dāng)state是STATE_LOADING,
                //那我們就知道要把最后一項的字變?yōu)椤凹虞d中”
                //并且要讓我寫在布局中的滾動條進(jìn)行顯示(一般在加載中才會有滾動條的顯示)
                //這時候調(diào)用我們的自定義方法loadMoreListener.onLoadMore();方法,這個方法是用來訪問后臺接口,然后去獲取數(shù)據(jù)的。
                case AdapterLoader.STATE_LOADING:
                    content.setText("加載中");
                    container.setOnClickListener(null);
                    pb.setVisibility(View.VISIBLE);
                    if (loadMoreListener != null) {
                        loadMoreListener.onLoadMore();
                    }
                    
                    break;
                  
                //2.當(dāng)state是STATE_LASTED的時候
                //最后一項的字變?yōu)椤皼]有更多了”
                //我們的加載進(jìn)度條也可以隱藏了
                case AdapterLoader.STATE_LASTED:
                    pb.setVisibility(View.GONE);       
                    container.setOnClickListener(null);
                    content.setText("---  沒有更多了  ---");

                    //大家還記不記得我們在監(jiān)聽滑動的時候,我們有個adapter.isHasMore()變量作為控制,
                    //當(dāng)我們的狀態(tài)已經(jīng)變?yōu)榱薙TATE_LASTED了。那我們也不需要再監(jiān)聽是否滑到了最底部了。因為已經(jīng)加載全部了。
                    adapter.setHasMore(false);

                    break;
                

                //3.當(dāng)state是STATE_ERROR的時候
                //最后一項的字變?yōu)椤凹虞d更多失敗點擊重試”
                //我們的加載進(jìn)度條也可以隱藏了
                //這里會跟其他二個狀態(tài)不同的地方,那就是當(dāng)加載失敗的時候,我們可以通過點擊這項,再去重新加載。
                //所以就要在最后一項中添加一個點擊事件。所以在其他二個狀態(tài)下,要重新設(shè)置setOnClickListener(null),來取消這個重新加載的點擊事件。
                case AdapterLoader.STATE_ERROR:
                    pb.setVisibility(View.GONE);
                    content.setText("--- 加載更多失敗點擊重試 ---");
                    container.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            if (loadMoreListener != null) {
                                loadMoreListener.onLoadMore();
                            }
                            content.setText("加載中");
                            pb.setVisibility(View.VISIBLE);
                        }
                    });

                    break;
                default:
                    break;
            }

        } else {
            //對具體的交易記錄的itemView進(jìn)行相應(yīng)的控件進(jìn)行處理。
            TransferExamItemBean bean = ((TransferExamItemBean) list.get(position));
            holder.itemView.setTag(bean);
            ((ExamRefreshAdapter.MyViewHolder) holder).name.setText(bean.getToCompanyName());
            ((ExamRefreshAdapter.MyViewHolder) holder).date.setText(bean.getCreateDate());
            ((ExamRefreshAdapter.MyViewHolder) holder).money.setText(bean.getAmount()+"");
        }
    }

好了,所以現(xiàn)在的情況是,滑到底部,然后通知去刷新底部的item,因為剛開始默認(rèn)是STATE_LOADING,所以在刷新創(chuàng)建這底部這項的時候,就會按照我們寫的判斷。出現(xiàn)加載框,文件顯示“加載中”,然后會運行我們寫的向后臺獲取數(shù)據(jù)的接口。然后我們只要在訪問后臺接口,根據(jù)返回的情況,適當(dāng)?shù)母牡撞縤tem的狀態(tài),然后再去刷新底部item,就可以了。

第五步:

我們滑到了底部,調(diào)用了我們的獲取數(shù)據(jù)的接口代碼,這時候我們要分三種情況來處理:

  1. 如果后臺給我們的是四個數(shù)據(jù),那說明有可能后面還會有數(shù)據(jù),那我們這時候拿到四條數(shù)據(jù)后,只需要在最后一項前面插入,這樣的話,最后一項的狀態(tài)也不需要改變。

這時候我們把新加載的四條數(shù)據(jù)插在<加載中>的前面,然后我們對于最后一項不需要做處理,這樣當(dāng)我們往下滑的時候。又會重新跑一遍上面的邏輯。(也就是再次看到最后一項,調(diào)用notifyItemRangeChanged方法,然后根據(jù)狀態(tài)去刷新最后一項,然后因為我們沒改變過狀態(tài),還是STATE_LOADING,所以又再去向后臺拿數(shù)據(jù)。)

我們在adapter中定義方法:

public final void appendList(List<T> data) {
        int positionStart = list.size();
        list.addAll(data);
        int itemCount = list.size() - positionStart;

        if (positionStart == 0) {
            notifyDataSetChanged();
        } else {
            notifyItemRangeInserted(positionStart + 1, itemCount);
        }
    }

假設(shè)我們已經(jīng)拿到了后臺給我們的list數(shù)據(jù),這時候我們判斷下這個list數(shù)據(jù)個數(shù)是不是等于4,如果等于4,我們就調(diào)用adapter.appendList(list)即可

2.如果后臺給你的數(shù)據(jù)是小于四個的,這時我們要設(shè)置我們的adapter中最后一項的狀態(tài)為STATE_LASTED,然后也要調(diào)用adapter.appendList(list);

3.查看后臺返回的json中的code值是不是200(比如code== 200說明獲取數(shù)據(jù)成功),我們獲取到的數(shù)據(jù)時候,就對code做判斷。如果不是200,那我們就把adapter中的狀態(tài)變?yōu)镾TATE_ERROR。然后再調(diào)用notifyItemRangeChanged去刷新一下最后一項即可。這樣最后一項就變成了<加載失敗>,并且具有了點擊重新加載的功能。

注意,比如我們已經(jīng)滑到最下面了。這時候去調(diào)用我們后臺的接口了。這時候,最好前面用一個boolean值去做判斷。比如下面這個方法是我的訪問后臺接口方法:

public void onLoadMore() {
        if (isRun) {
            return;
        }
        isRun = true;
        presenter.getTransferExamList("zjzt", lastOrderID);
    }

防止重復(fù)滑到下面去調(diào)用多次后臺接口,當(dāng)后臺接口返回數(shù)據(jù)后,再設(shè)置isRun = false即可。

我先大致寫到這里。后面再貼上完整的代碼,我主要先寫的還是對分頁加載來進(jìn)行分析。thanks。哪里不對,請指教。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,605評論 25 708
  • Android Studio JNI流程首先在java代碼聲明本地方法 用到native關(guān)鍵字 本地方法不用去實現(xiàn)...
    MigrationUK閱讀 11,914評論 7 123
  • 一、存量VS增量 晴晴小朋友愛書,更愛撕書,這是存量;奶奶開始教晴晴認(rèn)書上的圖案,背上面的古詩,現(xiàn)在書保存的很好,...
    萬事皆三閱讀 581評論 1 1
  • 倉促 還在清醒著的眼, 認(rèn)清了月亮上的季節(jié), 那里在飄灑銀色雪,落在地球 ——我們把她叫做月光。 喝下一杯紅酒,我...
    木紋青崖閱讀 322評論 3 6
  • 我們還是從一個段子開始吧: 優(yōu)酷土豆合并了,百度的愛奇藝成為了老二;滴滴快的合并了,百度投資的Uber成了老二;攜...
    咸魚姬閱讀 298評論 0 0