主頁 > 移動端開發 > 【小白做專案-02(仿知乎日報APP)】(聯網,webview,Recyclerview多item,Json決議,重繪加載)手把手教你Android實戰

【小白做專案-02(仿知乎日報APP)】(聯網,webview,Recyclerview多item,Json決議,重繪加載)手把手教你Android實戰

2021-02-11 12:47:18 移動端開發

【小白做專案-02】

本文為Karthus77原創轉載請說明

文章目錄

  • 【小白做專案-02】
    • 一、專案需求
    • 二、效果展示
    • 三、專案分析
    • 四、實戰操作
      • 1.專案框架搭建
        • 1.1 Activity搭建
        • 1.2 添加網路訪問權限
        • 1.3 添加依賴
      • 2.UI界面搭建
        • 2.1界面部分
        • 2.2狀態欄透明效果設定
      • 3.Recyclerview使用
        • 3.1 Recyclerview作業原理
        • 3.2 布局檔案中Recyclerview
        • 3.3 創建item布局
        • 3.4 創建Adapter
      • 4.網路訪問獲取資料
        • 4.1 Calender日歷獲取時間
        • 4.2 發送網路請求
        • 4.3 Json資料決議與Map,list儲存
        • 4.4 Adapter適配與多item
      • 5.重繪與加載
      • 6.WebView的使用
      • 7.評論展示與glide工具>
      • 8.斷網處理
    • 五、總結

一、專案需求

  1. 仿照“知乎日報APP”設計
  2. 輪播圖不做要求
  3. 評論樓中樓不做要求
  4. 用戶系統不做要求

二、效果展示

三、專案分析

仿照知乎日報這個專案,是一個較為復雜的APP專案
該專案的核心是“資料獲取”到“資料展示”的一個程序
核心知識點如下:

  1. Recyclerview多item
  2. Recyclview使用
  3. Json資料決議
  4. webview使用
  5. smartrefresh的使用
  6. 網路訪問獲取資料
  7. glide工具加載圖片

四、實戰操作

1.專案框架搭建

1.1 Activity搭建

該專案需要3個活動頁面

  1. 主頁面(展示新聞標題)
  2. 內容頁面(展示具體新聞內容)
  3. 評論頁面(展示用戶評論)

1.2 添加網路訪問權限


在AndroidManifest.xml檔案中加入以下兩行代碼,
并在<application下方加入以下代碼

 android:usesCleartextTraffic="true"

AndroidManifest是對應Android應用的一個組態檔,例如我在該檔案中加入了聯網許可,這個APP就可以聯網,

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

1.3 添加依賴

首先,什么是依賴,為什么要去添加它呢?
簡單的來說,依賴是一個程式,是一堆代碼,這段程式或代碼可以幫助我們解決很多問題,比如我們在寫C語言程式是,要include頭檔案,頭檔案中就已經為我們寫好了很多函式的定義,依賴就是如此,Android Studio內部沒有實作的功能,我們以依賴方式添加,就可以實作依賴中的功能,
需要說明的是,依賴雖好,可不要頻繁使用,因為依賴是別人寫出來的,內部的實作功能你了解的并不清晰,并不理解,此種利弊,需要自己好好考量
在這里插入圖片描述
在build.gradle中加入以下依賴(glide圖片加載工具,smartrefresh重繪工具,recyclerview視圖工具)

    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.2'
    implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.2'

2.UI界面搭建

2.1界面部分

由于UI界面參考“知乎日報APP”我們只需要模仿即可

我們只需要做出圖片中紅線包裹的UI即可

2.2狀態欄透明效果設定

我們可以看到紅框部分狀態欄是圖片背景的底色
設定方法,在xml檔案對應的Activity的onCreate周期后面加入以下代碼即可實作該效果

 if (Build.VERSION.SDK_INT >= 21){
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

3.Recyclerview使用

什么是Recyclerview呢?它有什么用呢?
通俗的話,Recyclerview就是一個強大的控制元件,用于重復展示某一類東西,展示的每一個東西叫做item

如圖中所示,每一個新聞就是Recyclerview中的一個item,同樣在我們QQ聊天為微信聊天的地方,每一個聯系人的小窗就是一個item,有了Recyclerview我們就可以做出知乎日報中新聞的效果了

3.1 Recyclerview作業原理

我們說Recyclerview是一個控制元件,也就是說它是類似與Textview,Editview的一種工具,我們在Activity中對Textview等可以進行一系列的操作,同樣,我們在Activity對Recyclerview進行操作,

Recyclerview既然要以一個形式重復展示多組資料(item),所以Recyclerview控制元件的本質功能就是“資料接收”到“資料展示”的一個工具,
那么如何進行資料的接受呢?資料的接受必須以一定的形式存貯起來,我們知道資料存貯的方式有陣列,有鏈表,有結構體,而資料的展示就要用到Adapter配接器,即根據資料適配對應的展示形式,
Adapter能夠將Recyclerview和Activity聯系在一起,來展示資訊,

3.2 布局檔案中Recyclerview

在xml檔案中加入Recyclerview

<com.scwang.smartrefresh.layout.SmartRefreshLayout
            android:id="@+id/refreshLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </com.scwang.smartrefresh.layout.SmartRefreshLayout>

由于需要重繪和加載功能,我們提前在Recyclerview中包裹我們的smartfresh

3.3 創建item布局

在這里插入圖片描述
在 layout檔案中新建一個layout XML file 檔案用于寫出每一條新聞檔案
分析每一條新聞布局
在這里插入圖片描述
可以看出每一個item有標題,小標題和圖片三部分
這里給出該item的xml的代碼

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/paper_item"
    android:layout_width="match_parent"
    android:layout_height="105dp">
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="100dp">


        <TextView
            android:id="@+id/titleArticle"
            android:layout_width="224sp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15sp"
            android:textSize="16sp"
            android:layout_marginTop="35sp"
            android:textStyle="bold"
            android:text="小事·懷孕,怕嗎?"
            android:textColor="@color/black">

        </TextView>
        <TextView
            android:id="@+id/viceTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12sp"
            android:layout_below="@id/titleArticle"
            android:layout_marginTop="5sp"
            android:text="VOL·1244"
            android:layout_marginLeft="15sp">

        </TextView>
        <ImageView
            android:id="@+id/imageTitle"
            android:layout_width="75sp"
            android:layout_height="75sp"
            android:layout_alignParentRight="true"
            android:layout_marginTop="25sp"
            android:layout_marginRight="15sp">

        </ImageView>
        <TextView
            android:id="@+id/everyday"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/viceTitle"
            android:text=""
            android:textSize="10sp"
            android:layout_marginLeft="50sp"
            android:layout_marginTop="10sp">

        </TextView>


    </RelativeLayout>

</LinearLayout>

3.4 創建Adapter

在這里插入圖片描述

新建Java Class 并命名為MyAdapater用于新聞類展示
Adapater里面的具體代碼我們在后面添加,先把它創建好

4.網路訪問獲取資料

我們在前面已經為專案添加了網路訪問的權限
下面我們就進行網路訪問的操作
首先網路訪問需要進行在子執行緒而不是主執行緒中
因為網路訪問是一個耗時操作
新建子執行緒

 final Thread thread=new Thread(new Runnable()

4.1 Calender日歷獲取時間

利用calender獲取當天的時間和早中晚來顯示紅框部分

代碼如下

final StringBuilder response = new StringBuilder();
                final StringBuilder response1 = new StringBuilder();
                String line;
                String line1;
                Calendar c=Calendar.getInstance();
                int t = c.get(Calendar.HOUR_OF_DAY);
                if(t>=18)
                {
                    time.setText("晚上好!");
                }
                else if(t<=8&&t>=6)
                {
                    time.setText("早上好!");
                }
                else
                {
                    time.setText("知乎日報");
                }
                int d=c.get(Calendar.DAY_OF_MONTH);
                String days=String.format("%d",d);
                Date.setText(days);

                int months=c.get(Calendar.MONTH);
                switch (months+1)
                {
                    case 1:month.setText("一月");
                    break;
                    case 2:month.setText("二月");
                    break;
                    case 3:month.setText("三月");
                    break;
                    case 4:month.setText("四月");
                    break;
                    case 5:month.setText("五月");
                    break;
                    case 6:month.setText("六月");
                    break;
                    case 7:month.setText("七月");
                    break;
                    case 8:month.setText("八月");
                    break;
                    case 9:month.setText("九月");
                    break;
                    case 10:month.setText("十月");
                    break;
                    case 11:month.setText("十一月");
                    break;
                    default:month.setText("十二月");

4.2 發送網路請求

我們已經新建了一個子執行緒,在這個子執行緒中進行聯網操作
先建立一個StringBulider獲取資料
StringBulider能夠將獲取的資料轉化成字串儲存起來

final StringBuilder response = new StringBuilder();
try {
                    URL url=new URL("https://news-at.zhihu.com/api/3/stories/latest");//獲取服務器哦地址
                    HttpURLConnection urlConnection= (HttpURLConnection) url.openConnection();//雙方建立連接

                    urlConnection.setRequestMethod("GET");//給服務器發送請求
                    InputStream inputStream=urlConnection.getInputStream(); //位元組流
                    Reader reader=new InputStreamReader(inputStream); //把位元組流轉化成字符流
                    BufferedReader bufferedReader=new BufferedReader(reader);//字符流 轉成 緩沖流,一次可以讀一行


                    while ((line=bufferedReader.readLine())!=null){//當temp讀到的資料為空就結束
                        response.append(line);

                    }

在這個程序中,url對應的是介面資料網站,setRequestMedthod設定訪問方式為get,利用readline函式以行方式讀取所有資料,讀完以后,所有資料已經存貯在response當中

4.3 Json資料決議與Map,list儲存

Json是一種易于理解的資料儲存形式,有著廣泛的應用,知乎日報官方Api回傳我們的是Json資料,因此我們需要將他決議,

我們用火狐瀏覽器打開介面網站,火狐瀏覽器會自動幫我們決議,便于理解
在這里插入圖片描述
決議Json資料需要理解物件與陣列
我們以latest這個介面為例,stories對應了當天的6篇文章的Json資料,也就說stories對應了一個Json陣列,這個陣列中有6個物件
在每個物件中有文章的大小標題,和對應封面圖片的Url
下面給出決議代碼

runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                JSONObject jsonObject = new JSONObject(String.valueOf(response));
                                date=jsonObject.getInt("date");
                                int day=date%100;
                                String days=String.format("%d",day);
                                JSONArray jsonArray = jsonObject.getJSONArray("stories");
                                for (int i = 0; i < 6; i++) {
                                    Map<String,Object> map=new HashMap<>();
                                    JSONObject jsonObject1 = (JSONObject) jsonArray.getJSONObject(i);
                                    String title = jsonObject1.getString("title");
                                    String vicetitle = jsonObject1.getString("hint");
                                    String url=jsonObject1.getString("url");
                                    String id=jsonObject1.getString("id");
                                    JSONArray jsonArray1=jsonObject1.getJSONArray("images");
                                    String imageUrl=(String)jsonArray1.get(0);
                                    map.put("url",url);
                                    map.put("id",id);
                                    map.put("image",imageUrl);
                                    map.put("title", title);
                                    map.put("hint",vicetitle);
                                    list.add(map);
                                }

                                myAdapter = new MyAdapter(Paper.this,list);
                                recyclerView.setAdapter(myAdapter);



runOnUiThread是回傳主執行緒的操作,由于UI操作只能在主執行緒中操作,而我們的聯網操作是在子執行緒中進行的操作,而我們需要將Json資料用Recyclerview的形式展示是UI操作所以需要回傳UI執行緒,也就是主執行緒

資料儲存在list當中,并利用map鍵值對的方式方便我們在Adpater中資料的獲取

4.4 Adapter適配與多item

 myAdapter = new MyAdapter(Paper.this,list);
                                recyclerView.setAdapter(myAdapter);

在Activity中就是這兩行代碼連接了Recyclerview和Adapter

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    private Paper context;
    private List<Map<String,Object>> list;
    private View inflater;
    private AdapterView.OnItemClickListener onItemClickListener;
    //構造方法,傳入資料
    public MyAdapter(Paper context, List<Map<String,Object>> list){
        this.context = context;
        this.list = list;
    }
    private static final int news = 0;
    private static final int date = 1;
    private static final int noNet= 2;
    @Override
    public int getItemViewType(int position) {
        int size=list.get(position).size();
        if (size==1)
        {
            return date;
        }
        else if(size==2)
        {
            return noNet;
        }
        else
        {
            return news;
        }
    }

在這段代碼中,我們利用getItemViewtype獲得需要展示的視圖

我們可以看到這里有兩種不同的item,所以我們的Recyclerview還要能夠適配多種item形式,getItemViewType就是獲取需要的Item我們以每條list中的大小(有幾個map鍵值對)來判斷對應的item種類

@Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //創建ViewHolder,回傳每一項的布局
        if(viewType==news)
        {
        inflater = LayoutInflater.from(context).inflate(R.layout.item,parent,false);
        ViewHolder ViewHolder = new ViewHolder(inflater);
        return ViewHolder;}
        else if(viewType==noNet)
        {
            inflater=LayoutInflater.from(context).inflate(R.layout.item_nonet,parent,false);
            noHolder noHolder=new noHolder(inflater);
            return  noHolder;
        }
        else
        {
            inflater = LayoutInflater.from(context).inflate(R.layout.item_date,parent,false);
            dateHolder dateHolder = new dateHolder(inflater);
            return  dateHolder;
        }
    }

在onCreatViewHolder中系結對應的item

@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        //將資料和控制元件系結
        int viewType=getItemViewType(position);
                if(viewType==0)
                {

           ViewHolder viewholder = (ViewHolder) holder;
           String number_title=list.get(position).get("title").toString();
           if(number_title.length()>27)
           {
               String title=number_title.substring(0,27);
               viewholder.titlePaper.setText(title+"...");
           }
           else{
               viewholder.titlePaper.setText(list.get(position).get("title").toString());
           }

        viewholder.titleVice.setText(list.get(position).get("hint").toString());
        Glide.with(context).load(list.get(position).get("image")).into(viewholder.titleImage);

        viewholder.paper_item.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(context,Context.class);
                Bundle bd=new Bundle();
                bd.putString("id",list.get(position).get("id").toString());
                bd.putString("url",list.get(position).get("url").toString());
                intent.putExtras(bd);
                context.startActivity(intent);

            }
        });}
                else if(viewType==2)
                {
                    noHolder noHolder=(noHolder) holder;
                    noHolder.hint.setText("網路好像走丟了");
                }
        else {

            dateHolder viewHolder = (dateHolder) holder;
            String day=list.get(position).get("date").toString();
            int nowDay=(Integer.parseInt(day)%100);
            int nowMonth=((Integer.parseInt(day)%10000)/100);
            viewHolder.date.setText(nowMonth+" 月 "+nowDay+" 日");}






    }

在onBindViewHolder中對需要用到的每一種item進行操作

 @Override
    public int getItemCount() {
        //回傳Item總條數
        return list.size();
    }

    //內部類,系結控制元件
    class ViewHolder extends RecyclerView.ViewHolder{
        LinearLayout paper_item;
        TextView titlePaper;
        TextView titleVice;
        ImageView titleImage;
        TextView everyday;
        public ViewHolder(View view) {
            super(view);
            everyday=view.findViewById(R.id.everyday);
            titlePaper= view.findViewById(R.id.titleArticle);
            titleVice= view.findViewById(R.id.viceTitle);
            titleImage = view.findViewById(R.id.imageTitle);
            paper_item=view.findViewById(R.id.paper_item);
        }
    }
    class dateHolder extends RecyclerView.ViewHolder{
        TextView date;
        TextView background;
        public dateHolder (View view){
            super(view);
            date=view.findViewById(R.id.newDate);
            background=view.findViewById(R.id.background);
        }
    }
    class noHolder extends RecyclerView.ViewHolder{
        TextView hint;
        public noHolder (View view){
            super(view);
            hint =view.findViewById(R.id.hint);
        }
    }

創建內部類系結每一種布局

5.重繪與加載

重繪與加載,聽起來就是很高級的功能啊,
如何去理解它呢,重繪與加載的本質其實就是兩個點擊事件,只不過是以滑動的形式表現出來的罷了,
重繪和加載的實質也是資料的更新與加載,我們利用Recyclerview加載item使用到的list資料,list的資料變多了,Recyclerview顯示的item也會變多

refreshLayout.setOnRefreshListener

這段代碼用于重繪事件的展開

refreshLayout.setOnLoadMoreListener

這段代碼用于加載事件,下面給出加載部分的完整代碼

 refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore(RefreshLayout refreshlayout) {
                refreshlayout.finishLoadMore(2000/*,false*/);//傳入false表示加載失敗
                final Thread thread=new Thread(new Runnable() {


                    @Override
                    public void run() {

                        final StringBuilder response1 = new StringBuilder();
                        String line1;
                        try {
                           yesterday=yesterday-1;

                            URL Url=new URL("https://news-at.zhihu.com/api/3/news/before/"+String.valueOf(yesterday));//獲取服務器哦地址
                            HttpURLConnection UrlConnection = (HttpURLConnection) Url.openConnection();//雙方建立連接
                            UrlConnection.setRequestMethod("GET");
                            InputStream inputStream1=UrlConnection.getInputStream();
                            Reader reader1=new InputStreamReader(inputStream1);
                            BufferedReader bufferedReader1=new BufferedReader(reader1);

                            while ((line1=bufferedReader1.readLine())!=null){//當temp讀到的資料為空就結束
                                response1.append(line1);

                            }

                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        JSONObject jsonObject = new JSONObject(String.valueOf(response1));
                                        JSONArray jsonArray = jsonObject.getJSONArray("stories");
                                        Map<String,Object> map1=new HashMap<>();
                                        Integer day1=jsonObject.getInt("date");
                                        map1.put("date",day1);
                                        list.add(map1);
                                        for (int i = 0; i < 6; i++) {
                                            Map<String,Object> map=new HashMap<>();
                                            JSONObject jsonObject1 = (JSONObject) jsonArray.getJSONObject(i);
                                            String title = jsonObject1.getString("title");
                                            String vicetitle = jsonObject1.getString("hint");
                                            String url=jsonObject1.getString("url");
                                            String id=jsonObject1.getString("id");
                                            JSONArray jsonArray1=jsonObject1.getJSONArray("images");
                                            String imageUrl=(String)jsonArray1.get(0);
                                            map.put("url",url);
                                            map.put("id",id);
                                            map.put("image",imageUrl);
                                            map.put("title", title);
                                            map.put("hint",vicetitle);
                                            list.add(map);
                                        }


                                        myAdapter.notifyDataSetChanged();

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

                                }
                            });
                            inputStream1.close();
                            reader1.close();
                            bufferedReader1.close();
                        } catch (Exception e) {
                           runOnUiThread(new Runnable() {
                               @Override
                               public void run() {
                                   list.clear();
                                   Map<String,Object> map=new HashMap<>();
                                   map.put("1",1);
                                   map.put("2",2);
                                   list.add(map);
                                   myAdapter = new MyAdapter(Paper.this,list);
                                   recyclerView.setAdapter(myAdapter);
                               }
                           });

                            e.printStackTrace();
//這里要有聯網失敗提示
                        }



                    }
                });
                thread.start();//啟動執行緒

            }
        });

6.WebView的使用

顧名思義,webview即網頁視圖的意思

對于每篇文章的內容部分我們使用webView控制元件即可

WebView webView=findViewById(R.id.webView);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.loadUrl(url);

僅僅三行代碼即可,其中的url是對應該文章的url地址

7.評論展示與glide工具>

glide的使用同樣需要添加依賴,我們已經在第一步的時候添加了glide的依賴,那么glide怎么使用呢

Glide.with(context).load(list.get(position).get("image")).into(viewholder.titleImage);

glide的使用只有一行代碼with部分是指當前的Activity,也就是context,load部分的get("image“),image是指所要加載圖片的url地址

評論部分的頭像圖片顯示為圓形,用glide工具可以加載圓形圖片

lide.with(context).load(list.get(position).get("image")).apply(RequestOptions.bitmapTransform(new CircleCrop())).into(viewholder.head);

用上面的代碼即可實作
評論部分的設計無需重繪加載,只需要用到多item即可,小伙伴們不妨自己嘗試去做
對了,每條評論下面的時間要自己寫演算法哦,因為介面傳過來的是一個很大的不知道怎么處理的數字,自己想想怎么能夠得到具體時間吧

8.斷網處理

我們的APP是需要聯網的,但是萬一你在沒有網的情況下打開它會怎么樣,
答案是:會閃退
所以我們需要做好斷網處理,斷網處理很簡單,我們在聯網操作時用到了
try{}catch結構
在這里插入圖片描述
我們如果沒有聯網,程式會進入catch部分,所以我們在catch部分進行斷網處理即可

catch (Exception e) {
                           runOnUiThread(new Runnable() {
                               @Override
                               public void run() {
                                   list.clear();
                                   Map<String,Object> map=new HashMap<>();
                                   map.put("1",1);
                                   map.put("2",2);
                                   list.add(map);
                                   myAdapter = new MyAdapter(Paper.this,list);
                                   recyclerView.setAdapter(myAdapter);
                               }
                           });

這是我catch部分的代碼,用于加載一個提示界面

效果如下

五、總結

總的來說,這是一個真正意義上的,可以說是一個成熟APP,作為練手專案,我很推薦,它有一定的難度,能夠充分考驗一個專案整體的架構能力,當然,整篇教程我在許多細節方面沒有詳細解答,因為我認為需要留有一部分自己思考,我認為能夠獨立做完這個專案,那么一定會對你的Android開發有著很大的提升,

該專案的源代碼和介面可以私信我即可,當然我可不是教大家做盜版軟體啊,純當小白自己練習,

下一個專案是一個淘寶類的專案,有個人用戶系統,可以上架購買商品,有興趣的小伙伴不妨關注一波~

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/258760.html

標籤:其他

上一篇:axios之post與get請求

下一篇:java開發環境的搭建

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more