Android 学习记录

目录

 

  • 关于SwipeRefreshLayout的坑
  • Rtrofit2使用详解
  • Parcelable和Serializable的使用
  • SQLiteDataBase
  • 关于activity及fragment生命周期的监听
  • 关于Android File.delete删除文件不够彻底的问题
  • 关于安卓7.0不允许使用Intent直接打开文件,必须使用FileProvider
  • android6.0以后某些敏感权限需要动态申请
  • 关于TransactionTooLargeException异常
  • Toolbar详解
  • 隐式意图
  • 动态监听wrap_content的布局宽高
  • Onkey事件无法响应
  • 关于Android File.delete删除文件不够彻底的问题
  • 在OnCreate中View.getHeight()无法获取宽高
  • 通过颜色过滤器或者tint来修改图标颜色
  • 截断TextView,设置不同颜色


一、关于SwipeRefreshLayout的坑

众所周知,SwipRefreshLayout可以手动停止刷新动画,只需要调用SwipeRefreshLayout.setRefreshing(false).可是当我们需要手动开启动画时候,SwipeRefreshLayout.setRefreshing(true)将不会生效。其真正的手动开启动画需要调用

 

SwipeRefreshLayout.post(new  Runnable(){
          Public void run(){
              SwipeRefreshLayout.setRefreshing(true)
          }
});

 

这样我们就可以实现手动调用动画了。

 

二、Rtrofit2使用详解

了解Retrofit2中的网络访问常用注解接口,其实这些接口都是在retrofit2.http这个包下面的

1、@GET GET网络请求方式
2、@POST POST网络请求方式
3、@Headers()头信息参数
4、@Path()路径参数,替换url地址中{ }所括的部分
5、@Query()查询参数,将在url地址中追加类似“page=1”的字符串,形成提交给服务端的请求参数
6、@QueryMap查询参数集合,将在url地址中追加类似
“type=text&username=abc&password=123”的字符串
7、@FormUrlEncoded对表单域中填写的内容进行编码处理,避免乱码
8、@Field()指定form表单域中每个空间的额name以及相应的数值
9、@FieldMap表单域集合
10、@Multipart Post提交分块请求,如果上传文件,必须指定Multipart
11、@Body Post提交分块请求

 //获取Retrofit对象,设置地址

        Retrofit retrofit = new Retrofit.Builder()

                .baseUrl("http://localhost")

                .client(OK_HTTP_CLIENT)//设置client 我们可以放入一个okhttpClient,便于我们设置超时时间

                .build();

  //创建RequstService

        创建你的RequstService接口类

        @GET

        //定义返回的方法,返回的响应体使用了ResponseBody

        Call<ResponseBody> getString(@Url String url);

        @FormUrlEncoded

        @POST

        Call<ResponseBody> post(@Url String url, @FieldMap Map<String, String> params);(post请求中用到了@FieldMap,所以必须在方法前加上@FormUrlEncoded否则将会报错)

        通过Rtrofit对象创建  retrofit.create(你的RequstService类);

   //发起请求如果是post请求需要传入一个map

    Call<ResponseBody> call = requestServices.post(url,pamars);

        call.enqueue(new Callback<ResponseBody>() {

            @Override

            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

                if (response.isSuccessful()){

                    try {

                        Log.i("cc",response.body().string());

                    } catch (IOException e) {

                        e.printStackTrace();

                    }

                }

            }

            @Override

            public void onFailure(Call<ResponseBody> call, Throwable t) {

                Log.i("cc","访问失败");

            }

        });

 

注意:关于retrofit2中baseurl的问题 如果设置了baseurl则可以在请求时传入接口进行拼接即可。

组合一://成功

baseUrl("http://api.m.mtime.cn/")

@GET("onebox/basketball/nba?key=98020a1e920819b8ff4fcfbdd7747f8c")  

Observable<NBA> getNBA2();

 

组合二://成功

baseUrl("http://api.m.mtime.cn/")

@GET("onebox/basketball/nba?key=98020a1e920819b8ff4fcfbdd7747f8c")  

Observable<NBA> getNBA2();

 

三、Parcelable和Serializable的使用

Parcel就是一个存放读取数据的容器, android系统中的binder进程间通信(IPC)就使用了Parcel类来进行客户端与服务端数据的交互,而且AIDL的数据也是通过Parcel来交互的。在Java空间和C++都实现了Parcel,由于它在C/C++中,直接使用了内存来读取数据,因此,它更有效率。

最重要的是其可以实现通过intent进行传递。

在使用时把需要传递的类implement Parcelable即可,完成其必要方法。

Serializable也是一个可传递的容器,它和Parcelable一样可以通过Bundle来进行传递,而且其实现更为简单,它就是一个java类,只需要直接implement Serializable即可,直接通过bundle.putSerializable()方法进行传递即可。

 

四、SQLiteDataBase

通过SQLiteDataBase来打开外部数据库。首先把数据库加载到本地,通过输入流实现。

   然后通过SQLiteDataBase来打开数据库

  Db = SQLiteDataBase.openOrCreateDatabase(dbfile,null);

查找

Cursor cursor = db.query(表名,null,null,null,null,null,null);//返回游标

查找结束后关闭游标。

 

五、关于activity及fragment生命周期的监听

在Application中可以监听所有activity的生命周期。在Activity中可以监听其所包含的fragment的生命周期。

activity生命周期的监听需要在application中调用registerActivityLifeecycleCallbacks方法

fragement生命周期的监听需要在其所属的activity中通过fragmentManager来调用registerFragementLifeecycleCallbacks方法

/**
     * 在activity内监听fragment的生命周期
     */
    public void setRegisterFragmentLifecycleCallbacks()
    {
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
            @Override
            public void onFragmentResumed(FragmentManager fm, Fragment f) {
                super.onFragmentResumed(fm, f);
            

            }

            @Override
            public void onFragmentPaused(FragmentManager fm, Fragment f) {
                super.onFragmentPaused(fm, f);
               
            }
        },false);

    }

 

六、关于Android File.delete删除文件不够彻底的问题

在调用file.delete方法前我们必须发送一条广播告诉手机我们准备删除该文件,以达到彻底删除文件。

Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
Intent.setData(uri);
Context.sendBroadcast(intent);
file.delete();

 

七、关于安卓7.0不允许使用Intent直接打开文件,必须使用FileProvider

使用FileProvider的方法

1、在mainfest中注册

           <provider  
            android:name="android.support.v4.content.FileProvider"  
            android:authorities="com.mydomain.fileprovider"  
            android:exported="false"  
            android:grantUriPermissions="true">  
       </provider>  

2、res文件下创建xml文件目录下创建新文件,内容如下:

    <file-path name="" path="">对应Context.getFilesDir();

     <cache-path name="" path="">对应getCacheDir();

     <external-path name="" path="">对应Environment.getExternalStorageDirectory();

     <external-cache-path name="" path="">对应Context.getExternalCacheDir();

3. Uri的创建   

Uri uri = getUriForFile(content,authorities,file);

4. 重点为URI临时授权

Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

 

八、android6.0以后某些敏感权限需要动态申请

 /**
 * 请求授权
 */
private void requestPermission(){
    if (Build.VERSION.SDK_INT >= 23) {
        int checkCallPhonePermission = ContextCompat.checkSelfPermission
                (this, Manifest.permission.CALL_PHONE);
        if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
            //在String[]中传入需要申请的权限
           ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }
        else{
            //sendHomework();
           //已经拥有了权限
          }
    }
    else {
    
    }
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,int[] grantResults) {
    switch (requestCode) {
        case 1:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //sendHomework();
                //获取权限成功后的处理
            }
            else {
               //showToast("fail");
                //获取权限失败的处理
            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

需要动态申请的权限

危险权限和权限组列表

 

九、关于TransactionTooLargeException异常

     该异常中文意思传输数据过大异常,造成该异常的原因应该是通过Bundle进行数据传输时,数据过大造成的,Bundle进行数据传输严格限制共享区域缓存大小只有1M。

     从以上异常的描述,可以总结出现该异常的原因:

  • 跨进程方法调用
  • 调用的方法带的参数或者返回值占用较多内存
  • 同一时刻方法调用次数太多

      解决办法

  • 压缩数据
  • 减少跨进程传输方法的调用
  • 减少同一时刻方法调用次数

 

十、Toolbar详解

  • setNavigationIcon:即设定 up button 的图标,因为 Material 的介面,在 Toolbar这里的 up button样式也就有別于过去的 ActionBar
  • setLogo:toolbar的图标
  • setTitle:主标题
  • setSubtitle:副标题

为NavigationIcon设置点击事件有两种不同的方法

(1)通过onOptionsItemSelected设置点击事件

  @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            finish();
        }
        return super.onOptionsItemSelected(item);
    }

(2)通过OnClickListener设置点击事件
 

 toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });

如果希望Menu里面的按钮常驻Toolbar还需要在Menu的xml文件的item添加下面这条属性

app:showAsAction="always"

注意:setNavigationIcon需要放在 setSupportActionBar之后才会生效

菜单直接在toolbar中创建子组件即可。

优点:在这样的架构设计下,ToolBar直接成了Layout中可以控制的东西,相对于过去的actionbar来说,设计与可操控性大幅提升

 

十一、隐式意图

隐式意图必须判断是否有应用可以打开该意图。

 Intent openAlbumIntent = new Intent();
        openAlbumIntent.setType("image/*");
        openAlbumIntent.setAction(Intent.ACTION_PICK);
        openAlbumIntent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        if (getPackageManager().resolveActivity(openAlbumIntent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
            startActivityForResult(openAlbumIntent, CHOOSE_PICTRUE);
        } else {
            showToast("打开图库失败");
        }

 

十二、动态监听wrap_content的布局宽高

mLl.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
               //通过布局上下左右运算后可获得布局宽高
            }
        });

 

十三、Onkey事件无法响应

    给布局添加OnkeyListener时,Onkey事件没有响应,因为可能其事件被父类拦截了所以我们需要在代码中加上一句获取焦点且响应OnKey事件的代码即可。

mLinearLayout.setFocusableInTouchMode(true);//设置获取焦点且响应OnKey事件

 

十四、关于Android File.delete删除文件不够彻底的问题

我们必须发送一条广播告诉手机我们已经删除了文件,以达到彻底删除文件。

Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
sendBroadcast(intent);
file.delete();

 

十五、在OnCreate中View.getHeight()无法获取宽高

我们可以通过一个Runnable来实现异步获取布局宽高

 mHiddenLayout.post(new Runnable() {
            @Override
            public void run() {
                mHiddenLayout.setVisibility(View.GONE);
                mHiddenViewMeasureHeight = mHiddenLayout.getHeight();
                isInitComplet = true;
            }
        });

 

十六、通过颜色过滤器或者tint来修改图标颜色

ColorFilter颜色过滤器

  /**
     * 修改图标的颜色
     * @param icon 要修改的图标
     */
    public void changeIconColor(ImageView icon,int color){
        if(icon!=null){
            float[] colorMatrix = new float[]{
                    0, 0, 0, 0, Color.red(color),
                    0, 0, 0, 0, Color.green(color),
                    0, 0, 0, 0, Color.blue(color),
                    0, 0, 0, (float) Color.alpha(color) / 255, 0
            };
            icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        }
    }

Tint和TintMode修改图标颜色

     <ImageView
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_centerHorizontal="true"
                android:src="@mipmap/ic_today_tab_48dp"
                tools:ignore="ContentDescription" 
                android:tint="@color/colorPrimary"
                android:tintMode="multiply"/>

 

十七、截断TextView,设置不同颜色

 private SpannableString formatSpannableString(Context context, String title, String content) {
            if (content == null) {
                content = "";
            }
            SpannableString result = new SpannableString(String.format(title, content));
            ForegroundColorSpan contentSpan = new ForegroundColorSpan(
                    ContextCompat.getColor(context, R.color.font_black_primary));
            result.setSpan(contentSpan,
                    result.length() - content.length(),
                    result.length(),
                    Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
            return result;
        }

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值