遇到的问题:

1.新建Activity,无法引入新的xml文件 setContentView(R.layout.myActivity)

2.android R.id找不到资源的问题

3.OKHttp无法访问http请求

4.安卓10无法对SD卡内容进行读写

5.存储目录

6.播放本地音乐

7.真机调试

8.更改app图标

9.安卓UI

10.OKHttp请求中使用Toast报错

11.okHttp post 发送语音文件

12.设置圆角按钮

13.封装toast方法

14.设置欢迎页、解决欢迎页暂时白屏问题

15.post请求提交表单

16.fragment中获取控件

17.fragment中更新UI报错 Only the original thread that created a view hierarchy can touch its views

18.BottomNavigationView 底部菜单多于3时,底部菜单显示不全

19.隐藏AppCompatActivity的默认标题栏

20.fragment中使用RecyclerView(RecyclerView代替原始控件ListView)

21.okhttp get请求带参数

22.gson 解析json数据

23.Only the original thread that created a view hierarchy can touch its views.(okhttp中更新视图报错)

24.RecyclerView 数据更新

25.输入法把底部菜单栏顶到上面

解决办法:

1.重启android studio解决,当然不是根本解决办法,但是这个最快最简单。

2.同上,重启androird studio即可解决

安卓10 在以往的读写权限之外还需要加入如下设置:①在 AndroidManifest.xml 中加入 android:requestLegacyExternalStorage=“true”

<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 读取SDCard数据权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

5.存储路径详解

链接

6.本地新建raw文件,raw文件下放音频文件(notice.mp3),使用MediaPlayer播放。

//播放按钮
    class PlayRecordListener implements View.OnClickListener{
        @Override
        public void onClick(View v) {


            MediaPlayer mPlayer = new MediaPlayer();
            AssetFileDescriptor file = mContext.getResources().openRawResourceFd(R.raw.notice);
            try{
                mPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
                mPlayer.prepare();
                mPlayer.start();
            }catch (IOException e){
                Log.e("fail","播放失败");
            }
        }
    }

7.真机调试
1.打开开发者选项
2.打开USB调试
3.下载 Google USB driver file->setting->android SDK->SDK Tools->下载Google USB driver
4.run 选择真机
5.允许安装

更多参见网址:
链接链接

8.更改app图标
链接

AndroidManifest.xml文件中的其中icon 和 roundIcon为app的图标设置,放置新的图标到drawable中,不要直接替换或删除原本的图标。

<application
android:allowBackup="true"
android:icon="@drawable/icon"
android:networkSecurityConfig="@xml/network_config"
android:label="@string/app_name"
android:roundIcon="@drawable/icon_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme"
tools:targetApi="n">

9.安卓UI


10.OKHttp中get请求调用Toast
提示错误信息:Can’t toast on a thread that has not called Looper.prepare()

Looper.prepare();

Toast.makeText(context, text, Toast.LENGTH_SHORT).show();

Looper.loop();

13.封装toast

1.新建toastUtils
2.新建APP
3.mainfests调用App,实例化toast对象
4.使用 App.toast.showToastMessage()

14.设置欢迎页

欢迎页空白,添加style样式文件,并应用到welcomeActivity页面

styles.xml

<style name="FullScreenWithBackground" parent="@style/Theme.AppCompat.Light">
    <item name="android:windowNoTitle">true</item>//无标题
    <item name="android:windowActionBar">false</item>//无ActionBar
    <item name="android:windowFullscreen">true</item>//全屏即无通知栏
    <item name="android:windowContentOverlay">@null</item>//是否有遮盖
    <item name="android:windowBackground">@mipmap/welcome</item>
</style>

mainfests.xml

<!--为解决欢迎页空白情况,添加style-->
<activity android:name=".Activity.WelcomeActivity" android:theme="@style/FullScreenWithBackground">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

链接

普通post请求报错 “Unsupported Media Type”,“message”:“Content type ‘application/x-www-form-urlencoded;charset=UTF-8’ not supported”,“path”:"/wx/login"

这是因为android的默认Media Type是"application/x-www-form-urlencoded;charset=UTF-8",而后台接口要的是“application/json; charset=utf-8”格式。

关键代码:设置requestBody的content-type

MediaType JSON = MediaType.parse("application/json; charset=utf-8");
            JSONObject json = new JSONObject();
            json.put("wxUserAccount","13243210010");
            json.put("wxUserPassword","123456aaa");
  RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), json.toString());

完整post请求如下:

new Thread(new Runnable() {//在这个方法中同样还是先开启了一个子线程
    @Override
    public void run() {
        try {
            MediaType JSON = MediaType.parse("application/json; charset=utf-8");
            JSONObject json = new JSONObject();
            json.put("wxUserAccount","13243210010");
            json.put("wxUserPassword","123456aaa");
            String http_url = "http://192.168.1.50:8080/v1/api/wx/login";
            OkHttpClient client = new OkHttpClient();
            RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), json.toString());
            Log.i("respBody", String.valueOf(requestBody));
            Request request = new Request.Builder()
                    .url(http_url)
                    .post(requestBody)
                    .build();
            Response response = client.newCall(request).execute();//接收服务器返回的数据
            String responseData = response.body().string();//得到具体数据
            Log.i("resp", responseData);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}).start();

16.fragment中获取控件

对比在Activity中获取控件直接通过findViewById(),在fragment中需要添加View名称

public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
    View root = inflater.inflate(R.layout.fragment_home, container, false);
    // 获取控件
    test_btn= (Button) root.findViewById(R.id.test_btn);
    return root;
}

链接

17.fragment中更新UI报错
链接

android中相关的view和控件不是线程安全的,我们必须单独做处理。这里借此引出Handler的使用。

package djx.android;
import djx.downLoad.DownFiles;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;


public class downLoadPractice extends Activity {
    private Button button_submit=null;
    private TextView textView=null;
    private String content=null;
    private Handler handler=null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //创建属于主线程的handler
        handler=new Handler();
        
        button_submit=(Button)findViewById(R.id.button_submit);
        textView=(TextView)findViewById(R.id.textView);
        button_submit.setOnClickListener(new submitOnClieckListener());
    }
    //为按钮添加监听器
    class submitOnClieckListener implements OnClickListener{
        @Override
        public void onClick(View v) {
//本地机器部署为服务器,从本地下载a.txt文件内容在textView上显示            
            final DownFiles df=new DownFiles("http://192.168.75.1:8080/downLoadServer/a.txt");
            textView.setText("正在加载......");
            new Thread(){
                public void run(){    
                    content=df.downLoadFiles();        
                    handler.post(runnableUi);
                    }                    
            }.start();                        
        }
        
    }

   // 构建Runnable对象,在runnable中更新界面
    Runnable   runnableUi=new  Runnable(){
        @Override
        public void run() {
            //更新界面
            textView.setText("the Content is:"+content);
        }
        
    };
}

18.BottomNavigationView 底部菜单多于3时,底部菜单显示不全

设置属性:app:labelVisibilityMode=“labeled” 即可。
更多相关知识:
链接

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/nav_view"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="0dp"
    android:layout_marginEnd="0dp"
    android:background="?android:attr/windowBackground"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:labelVisibilityMode="labeled"
    app:menu="@menu/bottom_nav_menu" />

19.隐藏AppCompatActivity的默认标题栏
在onCreate()之后设置属性 getSupportActionBar().hide(); 即可。

链接

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

getSupportActionBar().hide(); // 隐藏AppCompatActivity的标题栏

20.fragment中使用RecyclerView

链接

1.添加依赖

implementation 'com.android.support:recyclerview-v7:29.0.0'

2.新建ListView,列表容器

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/collect_recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>

3.新建list-item,列表项此为列表项中每一项的样式文件

4.自定义实体类 Entity文件下新建实体类

  1. 设置RecyclerView的适配器 Adapter文件下新建适配器

6.解析数据 Bean文件下根据返回json数据结构解析数据

7.应用

通过okhttp获取到数据,在调用Recycler方法

if(gasDataBean.getCode() == 200) {
    for (int i = 0; i < gasDataBean.getData().getList().size(); i++) {
        GasDataBean.DataBean.ListsBean b = gasDataBean.getData().getList().get(i);
        GasEntity gasEntity = new GasEntity();
        gasEntity.setCh4(b.getCh4());
        gasEntity.setCo(b.getCo());
        gasEntity.setO2(b.getO2());
        gasEntity.setHumidity(b.getHumidity());
        gasEntity.setTemperature(b.getTemperature());
        gasEntity.setStaff_name(b.getStaffname());
        gasEntity.setGroup_name(b.getGroupName());
        gasEntity.setTemppositionname(b.getTemppositionname());
        gasEntity.setCreatetime(b.getCreatetime());
        gasEntityArrayList.add(gasEntity);
    }
    handler.post(runnableUi);
}


private void initRecyclerView() {
    //获取RecyclerView
    mCollectRecyclerView=(RecyclerView)gas.findViewById(R.id.collect_recyclerView);
    //创建adapter
    mCollectRecyclerAdapter = new GasListAdapter(getActivity(), gasEntityArrayList);
    //给RecyclerView设置adapter
    mCollectRecyclerView.setAdapter(mCollectRecyclerAdapter);
    //设置layoutManager,可以设置显示效果,是线性布局、grid布局,还是瀑布流布局
    //参数是:上下文、列表方向(横向还是纵向)、是否倒叙
    mCollectRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
    //设置item的分割线
    mCollectRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(),DividerItemDecoration.VERTICAL));
    //RecyclerView中没有item的监听事件,需要自己在适配器中写一个监听事件的接口。参数根据自定义
    mCollectRecyclerAdapter.setOnItemClickListener(new GasListAdapter.OnItemClickListener() {
        @Override
        public void OnItemClick(View view, GasEntity data) {
            //此处进行监听事件的业务处理
            Toast.makeText(getActivity(),"我是item",Toast.LENGTH_SHORT).show();
        }
    });
}

21.okhttp get请求带参数

Request.Builder reqBuild = new Request.Builder();
HttpUrl.Builder urlBuilder =HttpUrl.parse("https://api.weibo.com/2/users/show.json")
                                    .newBuilder();
urlBuilder.addQueryParameter("access_token", oauth2AccessToken.getToken());
urlBuilder.addQueryParameter("uid", oauth2AccessToken.getUid());
reqBuild.url(urlBuilder.build());
Request request = reqBuild.build();

23.Only the original thread that created a view hierarchy can touch its views.(okhttp中更新视图报错)

使用handler

// 声明变量
private Handler handler;
// 初始化 onCreate中
handler = new Handler();
// 调用 okhttp中
handler.post(runnableUi);

// 构建Runnable对象,在runnable中更新界面
private Runnable runnableUi =new  Runnable(){
    @Override
    public void run() {
        //更新界面
        initRecyclerView();
    }
};

24.RecyclerView 数据更新

查询功能,先清空列表,后查询

code == 111 清空列表

gasEntityArrayList.clear();
mCollectRecyclerAdapter.notifyDataSetChanged();

dataList.clear(); //去掉之前的数据
dataList.add(weather); //添加新的Weather对象
mAdapter.notifyDataSetChanged(); // 清空recyclerView

25.输入法把底部菜单栏顶到上面

android:windowSoftInputMode="adjustPan"
android:windowSoftInputMode="adjustPan"
<activity
android:name=".IndexActivity"
android:windowSoftInputMode="adjustPan"
android:label="@string/title_activity_index"/>