Android小提示六

简介: Android一些小提示

@[TOC]

【82.Context启动startActivity注意】

intent.setFlags() 方法中参数的用例:

很多人在使用 startActivity时候,会碰到如下异常:
Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

都知道,Context中有一个startActivity方法。Activity继承自Context,重载了startActivity方法,如果使用Activity的startActivity方法不会有任何限制。而如果使用Context的startActivity方法的话,就需要开启一个新的task,遇到上面的异常就是因为此。

解决办法:代码中加一个flag,即Intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).这样就可以在新的task里启动这个Activity了。

【83.Android调用各系统界面】

API文档

startActivity(new Intent(Settings.ACTION_SETTINGS)); //系统设置界面

String pkg = context.getApplicationInfo().packageName;
int uid = context.getApplicationInfo().uid;

//有些特殊界面是没办法打开的,例如NFC等设置界面,需要手机硬件支持.
ACTION_APPLICATION_DETAILS_SETTINGS   apk详情界面
intent.setData(Uri.parse("package:" + ));

ACTION_APP_NOTIFICATION_SETTING;    apk通知界面
    //API26 8.0以上
intent.putExtra(Settings.EXTRA_APP_PACKAGE, pkg);
intent.putExtra(Settings.EXTRA_CHANNEL_ID, uid);
    //API21-25 5.0-7.1
intent.putExtra("app_package", pkg);
intent.putExtra("app_uid", pkg);

ACTION_SETTINGS                    系统设置界面

ACTION_DATA_ROAMING_SETTINGS      双卡和移动网络设置界面
ACTION_WIFI_SETTINGS              无线网设置界面
ACTION_VPN_SETTINGS               VPN设置界面,可能不存在
ACTION_WIFI_IP_SETTINGS           WIFI的IP设置
ACTION_BLUETOOTH_SETTINGS         蓝牙设置
ACTION_DATE_SETTINGS              日期时间设置
ACTION_LOCALE_SETTINGS            语言设置
ACTION_SOUND_SETTINGS             声音设置
ACTION_SECURITY_SETTINGS          安全设置界面

ACTION_ACCESSIBILITY_SETTINGS     无障碍设置/辅助功能界面
ACTION_ADD_ACCOUNT                添加账户界面
ACTION_AIRPLANE_MODE_SETTINGS      更多连接方式设置界面
ACTION_APN_SETTINGS                APN设置界面
ACTION_APPLICATION_DEVELOPMENT_SETTINGS     开发者选项设置
ACTION_APPLICATION_SETTINGS        应用程序列表界面
    ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS  //【所有的】
    ACTION_MANAGE_APPLICATIONS_SETTINGS      //【已安装的】

ACTION_BATTERY_SAVER_SETTINGS     节电助手界面
ACTION_CAPTIONING_SETTINGS        字幕设置的界面
ACTION_CAST_SETTINGS              投射设置    //【API 17及以上】
ACTION_DEVICE_INFO_SETTINGS       手机状态信息的界面
ACTION_DREAM_SETTINGS             互动屏保设置的界面
ACTION_DISPLAY_SETTINGS           手机显示设置
ACTION_HOME_SETTINGS              主屏幕设置界面
ACTION_INPUT_METHOD_SETTINGS      语言和输入法设置
ACTION_INPUT_METHOD_SUBTYPE_SETTINGS 多国语言选择
ACTION_INTERNAL_STORAGE_SETTINGS  存储空间设置的界面
ACTION_MEMORY_CARD_SETTINGS       记忆卡存储
ACTION_LOCATION_SOURCE_SETTINGS    定位设置界面
ACTION_NETWORK_OPERATOR_SETTINGS  选取运营商的界面
ACTION_NFCSHARING_SETTINGS        显示NFC共享设置  //【API 14及以上】
ACTION_NFC_SETTINGS               显示NFC设置     //【API 16及以上】
ACTION_NOTIFICATION_LISTENER_SETTINGS       通知使用权设置的界面
ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS  勿扰权限设置的界面

ACTION_PRINT_SETTINGS             打印设置界面
ACTION_PRIVACY_SETTINGS           备份重置设置界面
ACTION_QUICK_LAUNCH_SETTINGS      跳转快速启动设置界面
ACTION_SEARCH_SETTINGS            搜索设置界面
ACTION_SYNC_SETTINGS              同步设置界面
ACTION_USER_DICTIONARY_SETTINGS   个人字典设置界面
ACTION_VOICE_INPUT_SETTINGS       辅助应用和语音输入设置

【84.view淡入淡出效果】

淡入

View mContentView;
mContentView.setAlpha(0f);
mContentView.setVisibility(View.VISIBLE);
mContentView.animate()
        .alpha(1f)
        .setDuration(300)
        .setListener(null);
        
//Kotlin
private lateinit var mContentView: View
mContentView.apply {
    // Set the content view to 0% opacity but visible, so that it is visible
    // (but fully transparent) during the animation.
    alpha = 0f
    visibility = View.VISIBLE

    // Animate the content view to 100% opacity, and clear any animation
    // listener set on the view.
    animate()
            .alpha(1f)
            .setDuration(mShortAnimationDuration.toLong())
            .setListener(null)
}

淡出

private View mLoadingView;
mLoadingView.animate()
            .alpha(0f)
            .setDuration(mShortAnimationDuration)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mLoadingView.setVisibility(View.GONE);
                }
            });
            
//Kotlin
private lateinit var mLoadingView: View
mLoadingView.animate()
            .alpha(0f)
            .setDuration(mShortAnimationDuration.toLong())
            .setListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    mLoadingView.visibility = View.GONE
                }
            })

【85.view绘制监听】

//view??
addOnPreDrawListener
//view重绘时回调
view.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {      
    @Override
    public void onDraw() {
  
    }
});

//view加载完成时回调(布局的状态发生变化或者可见性发生变化才会调用)
view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
       //todu 这里写你要在界面加载完成后执行的操作。
        view.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
    }
});

OnPreDrawListener

在调用onDraw()方法之前调用.此时,树中的所有视图都已经过测量并给出了一个框架.因此,您可以在此回调中正确操作视图

OnGlobalLayoutListener

这个监听器被调用: – 当可见性状态发生变化时在示例中,当绘制视图时,它变得可见,并且会调用它. – 当你添加View视图树的变化时

【86.Android危险权限】

权限

普通权限直接在清单配置即可,危险权限需要用户手动动态申请。当用户同意了某一个权限时,那么该权限所对应的权限组下的所有其他权限也会同时被授权。
其中 Intent.ACTION_DIAL表示打开拨号界面,不需要动态权限。 Intent.ACTION_CALL则需要。

[](ttp://developer.android.com/reference/android/Manifest.permission.html) 系统完整权限列表。

【87.在不用事件总线时 处理方法】

1.广播

class ActivityA extends Activity{
    ..onCreate(..){
        receiver = new BroadcastReceiver(){
            @Override
            public void onReceive(Context context, Intent intent){
                User user=intent.getParcelableExtra("user");
                //do sth
            }
        };
        registerReceiver(receiver, new IntentFilter("my_action"));
    }
    
    ..onDestroy(..){
        unregisterReceiver(receiver);
    }
}

class ActivityB extends Activity{
    ..onCreate(..){
        Intent intent = new Intent("my_action");
        intent.putExtra("user", new User("zxx"));
        
        sendBroadcast(intent);
    }
}

class User implements Parcelable{
    String name;
    ....
}

2.接收来自子线程的消息

class ActivityA extends Activity{
    ..onCreate(..){
        //创建一个子线程
        new Thread(new Runnable(){
            @Override
            public void run(){
                User user = new User("来自子线程");
                Message msg=mHandler.obtainMessage();
                msg.what=1;
                msg.obj=user;
                
                mHandler.sendMessage(msg);
            }
        }).start();
    }
    
    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            if(msg.what==1){
                User user= (User)msg.obj;
                //do sth 接收来自子线程的消息
            }
        }
    }
}

3.请使用 EventBus

[](https://github.com/hehonghui/AndroidEventBus)
[](https://github.com/greenrobot/EventBus/)
与EventBus、otto的特性对比

名称 订阅函数是否可执行在其他线程 特点
greenrobot的EventBus 使用name pattern模式,效率高,但使用不方便。
square的otto 使用注解,使用方便,但效率比不了EventBus。
AndroidEventBus 使用注解,使用方便,但效率比不上EventBus。订阅函数支持tag(类似广播接收器的Action)使得事件的投递更加准确,能适应更多使用场景。

【88.多线程】

runnable 解决java单继承冲突的,重写的run 方法是task的核心,未开启的thread 跟runnable区别不大。
runnable本身跟线程没啥关系啊,只是作为对任务task 的包装,还是要作为载体加到thread 中去的。
无论用runnable还是thread 都需要 开启线程 new Thread ,start()

四种多线程的创建方法

第一种:继承Thread类:

1.创建一个继承于Thread类的子类
2.重写Thread类的run() 将此线程执行的的操作声明在run()中
3.创建Thread类的子类的对象
4.通过此对象调用start()

//  1.创建一个继承于Thread类的子类
class MyThread extends Thread {
    //2.重写Thread类的run()
    @Override
    public void run() {
        for (int i = 0;i < 100 ;i++){
            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public static void main(String[] args) {
    //3.创建Thread类的子类的对象
    MyThread myThread = new MyThread();
    //4.通过此对象调用start()  ①启动当前线程 ②调用当前线程的run()
    myThread.start();

    //不能通过myThread.run()的方式启动线程

    //再启动一个线程
    MyThread myThread1 = new MyThread();
    myThread1.start();

    //如下操作仍然是在main()线程中执行的
    for (int i = 0;i < 100 ;i++){
        if (i % 2 != 0){
            System.out.println(Thread.currentThread().getName() + ":"+"hello");
        }
    }
}

第二种:实现Runnable接口:

1.创建一个实现了Runnable接口的类
2.实现类去实现Runnable中的抽象方法:run()
3.创建实现类的对象
4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start()

开发中优先选择实现Runnable接口的方式
 * 原因:1.实现的方式没有类的单继承性的局限性
 *      2.实现的方式更适合来处理多个线程有共享数据的情况
*
* 联系:都实现了Runnable接口
* 相同点:两种方式都需要重写run()方法,将线程要执行的逻辑声明在run()中

// * 1.创建一个实现了Runnable接口的类
class MyThread implements Runnable{
    // * 2.实现类去实现Runnable中的抽象方法:run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public static void main(String[] args) {
    // * 3.创建实现类的对象
    MyThread myThread = new MyThread();
    // * 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
    Thread thread1 = new Thread(myThread);
    // * 5.通过Thread类的对象调用start() ①启动线程 ②调用当前线程的run()
    thread1.start();

    Thread thread2 = new Thread(myThread);
    thread2.start();
}

第三种:实现Callable接口:JDK5.0新增

1.创建一个实现Callable的实现类
2.实现call方法,将此线程需要执行的操作声明在call()中
3.创建Callable接口实现类的对象
4.将Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法
6.获取Callable中call方法中的返回值
 * 如何理解实现Callable接口的方式创建多线程的方式比是实现Runnable接口创建多线程方式强大
 * 1.call()可以有返回值
 * 2.call()可以抛出异常
 
//1.创建一个实现Callable的实现类
class NumThread implements Callable{
    //2.实现call方法,将此线程需要执行的操作声明在call()中
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if(i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

public static void main(String[] args) {
    //3.创建Callable接口实现类的对象
    NumThread numThread = new NumThread();
    //4.将Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
    FutureTask futureTask = new FutureTask(numThread);

    //5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法
    Thread thread1 = new Thread(futureTask);
    thread1.start();

    try {
        //6.获取Callable中call方法中的返回值
        //get()返回值即为FutureTask构造器参数Callable实现重写的call()返回值。
        Object sum = futureTask.get();
        System.out.println(" 总和为:" + sum);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

第四组:线程池的方式:

1.提供指定线程数量的线程池
2.执行指定线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象

/**
 * 创建线程的方式四:使用线程池
 *
 * 好处:1.提高响应速度(减少创建新线程的时间)
 *      2.降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
 *      3.便于线程管理
 *
 *      corePoolSize:核心池的大小
 *      maximumPoolSize:最大线程数
 *      keepAliveTime:线程没有任务时最多保持多长时间后会终止
 */

public class ThreadPool {
    public static void main(String[] args) {
        //1.提供指定线程数量的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) executorService;
        //设置线程池的属性
        service1.setCorePoolSize(10);

        //2.执行指定线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
        executorService.execute(new NumberThread());//适合使用于Runnable

        //executorService.submit();//适合使用与Callable
        executorService.execute(new NumberThread1());
        //关闭线程池
        executorService.shutdown();
    }
}

class NumberThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i <= 100 ; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" +i);
            }
        }
    }
}

class NumberThread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i <= 100 ; i++) {
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ":" +i);
            }
        }
    }
}

Handler开启线程:这个并没有开启新线程

private Handler mHandler=new Handler();
mHandler.postDelayed(gotoLoginAct, 2000);//post(r)

Runnable gotoLoginAct = new Runnable() {
        @Override
        public void run() {
            Log.e("gotoLoginAct ");
            mHandler.removeCallbacks(gotoLoginAct);//停止线程
        }
    };

//上面这个并没有开启新线程,而要用
HandlerThread handlerThread = new HandlerThread("handlerThread");
handlerThread.start();
MyHandler handler = new MyHandler(handlerThread.getLooper());

【标题导航栏】

values-21这个文件夹,这个文件夹就是指只会在API21以上才会使用
[]

标题栏
通知栏,标题栏,视图框,导航栏

<item name="android:navigationBarColor">@color/colorPrimary</item>

/**
 * Set the navigation bar's color.
 * 该方法是在Android5.0中才加入的,而且在设置之前还需要判断手机是否支持虚拟导航栏。
 * @param window The window.
 * @param color  The navigation bar's color.
 */
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public static void setNavBarColor(@NonNull final Window window, @ColorInt final int color) {
    window.setNavigationBarColor(color);
}

/**
 * Return whether the navigation bar visible.
 *
 * @return {@code true}: yes<br>{@code false}: no
 */
public static boolean isSupportNavBar() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        WindowManager wm = (WindowManager) BaseApplication.getsApplication().getSystemService(Context.WINDOW_SERVICE);
        if (wm == null) return false;
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        Point realSize = new Point();
        display.getSize(size);
        display.getRealSize(realSize);
        return realSize.y != size.y || realSize.x != size.x;
    }
    boolean menu = ViewConfiguration.get(BaseApplication.getsApplication()).hasPermanentMenuKey();
    boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
    return !menu && !back;
}

如果要想改变导航栏按键的颜色,需要设置属性:windowLightNavigationBar为true,也可以在代码中调用方法:

View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);

需要注意的是,该API是在27中才加入的。
总结一下:

  • 设置导航栏背景色:设置navigationBarColor属性即可;
  • 改变导航栏按键颜色为深色:设置标志位View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,或者属性中设置windowLightNavigationBar为true;

Activity设置横屏、竖屏的方法

<activity android:name=".MyAcitivty" android:screenOrientation="landscape" />
注:landscape为横屏,portrait为竖屏。

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
注:SCREEN_ORIENTATION_LANDSCAPE为横屏,SCREEN_ORIENTATION_PORTRAIT为竖屏。

【时间】

[]

SystemClock.elapsedRealtime()  &  SystemClock.elapsedRealtimeNanos
    这个值与SystemClock.upTimeMillis()类似。它是系统启动到当前时刻经过的时间,包括了系统睡眠经过的时间。在CPU休眠之后,它依然保持增长。所以它适合做更加广泛通用的时间间隔的统计。
System.currentTimeMillis()   标准的“墙”时钟(时间和日期),表示从纪元到现在的毫秒数。
                    如果你使用System.currentTimeMillis(),可以考虑监听ACTION为ACTION_TIME_TICK、 
                    ACTION_TIME_CHANGED、ACTION_TIMEZONE_CHANGED 的广播去监听时间变化。

SystemClock.uptimeMillis()  表示自系统启动时开始计数,以毫秒为单位。
                    返回的是从系统启动到现在这个过程中的处于非休眠期的时间。当系统进入深度睡眠时(CPU关闭,设备变黑,等待外部输入装置)该时钟会停止。
                    但是该时钟不会被时钟调整,闲置或其他节能机所影响。这是大多数间隔时间的基本点,例如Thread.sleep(millls)、Object.wait(millis)和System.nanoTime()。该时钟被保证是单调的,适用于检测不包含休眠的间隔时间的情况。

SystemClock.elapsedRealtime() & SystemClock.elapsedRealtimeNanos()
                    返回系统启动到现在的时间,包含设备深度休眠的时间。该时钟被保证是单调的,即使CPU在省电模式下,该时间也会继续计时。该时钟可以被使用在当测量时间间隔可能跨越系统睡眠的时间段。

SystemClock.

  • 1、public static long currentThreadTimeMillis () 返在当前线程运行的毫秒数。
  • 2、public static long elapsedRealtime () 返回系统启动到现在的毫秒数,包含休眠时间。
  • 3、public static long elapsedRealtimeNanos () 返回系统启动到现在的纳秒数,包含休眠时间。
  • 4、public static boolean setCurrentTimeMillis (long millis) 设置当前的"墙"时间,要求调用进程有许可权限。返回是否成功。
  • 5、public static void sleep (long ms) 等待给定的时间。和Thread.sleep(millis)类似,但是它不会抛出InterruptedException异常。事件被推迟到下一个中断操作。该方法直到指定的时间过去才返回。
  • 6、public static long uptimeMillis () 返回系统启动到现在的毫秒数,不包含休眠时间。就是说统计系统启动到现在的非休眠期时间。

【89.ImageView加载图片】

//设置网络图片
public void setImageURL(final String path) {
    //开启一个线程用于联网
    new Thread() {
        @Override
        public void run() {
            try {
                //把传过来的路径转成URL
                URL url = new URL(path);
                //获取连接
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                //使用GET方法访问网络
                connection.setRequestMethod("GET");
                //超时时间为10秒
                connection.setConnectTimeout(10000);
                //获取返回码
                int code = connection.getResponseCode();
                if (code == 200) {
                    InputStream inputStream = connection.getInputStream();
                    //使用工厂把网络的输入流生产Bitmap
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    //利用Message把图片发给Handler
                    Message msg = Message.obtain();
                    msg.obj = bitmap;
                    msg.what = GET_DATA_SUCCESS;
                    handler.sendMessage(msg);
           inputStream.close();
                }else {
                    //服务启发生错误
                    handler.sendEmptyMessage(SERVER_ERROR);
                }
            } catch (IOException e) {
                e.printStackTrace();
                //网络连接错误
                handler.sendEmptyMessage(NETWORK_ERROR);
            }
        }
    }.start();
}

Glide缓存-介绍郭霖
[]

这个diskCacheStrategy()方法基本上就是Glide硬盘缓存功能的一切,它可以接收五种参数:

DiskCacheStrategy.NONE: 表示不缓存任何内容。
DiskCacheStrategy.DATA: 表示只缓存原始图片。
DiskCacheStrategy.RESOURCE: 表示只缓存转换过后的图片。
DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。
DiskCacheStrategy.AUTOMATIC: 表示让Glide根据图片资源智能地选择使用哪一种缓存策略(默认选项)。
其中,DiskCacheStrategy.DATA对应Glide 3中的DiskCacheStrategy.SOURCE,
DiskCacheStrategy.RESOURCE对应Glide 3中的DiskCacheStrategy.RESULT。
而DiskCacheStrategy.AUTOMATIC是Glide 4中新增的一种缓存策略,并且在不指定diskCacheStrategy的情况下默认使用就是的这种缓存策略。

Glide加载网络图片,

显示之前的URL图片,换了URL图片还是没变的问题

1、每次加载都清理缓存。这是个很垃圾的解决方法,相当于舍弃了缓存这个非常重要的功能。

.diskCacheStrategy(DiskCacheStrategy.NONE)  //禁用磁盘缓存
.skipMemoryCache(true);   //跳过内存缓存

2、图片地址采用:url+?随机数。当图片更换的时候,后台改变随机数就可以,这样你本地就会重新加载网络图片。如果后台没有这样做那你可以自己加随机数,在url后面添加“?”和随机的key+随机数,通过Math.random()返回一个0到1之间的double值。

Glide.with(getContext())
    .load(url + "?key=" + Math.random())
    .centerCrop()
    .into(imageUser);
    

3、使目标图片显示的所有地方均更新为服务器新数据——治本,永久性

  在加载图片的时候调用下方给出的updateOptions()方法(PS:这个方法可以放在工具类中使用),给RequestOptions指定signature属性,当modified改变时,Glide会判断为新图片,并且重新缓存,这样加载的就是服务器最新图片了。
这个要求后台要有修改的时间变量。
/**
 * RequestOptions 一般指定以下属性即可
 *  placeholder : 图片加载时的站位图,可使用loading动画或默认图片
 *  error : 图片加载失败时的显示图片
 *  diskCacheStrategy : 图片缓存路径
 */
RequestOptions options = new RequestOptions()
                .placeholder(R.drawable.bg_round_graylight10)
                .error(R.drawable.def_avatar)
               .diskCacheStrategy(DiskCacheStrategy.DATA);
               
 /**
 * 刷新RequestOptions,解決Glide图片缓存导致不刷新问题
 * 
 * @param options  
 * @param url       图片地址
 * @param modified  图片修改时间
 */
public static void updateOptions(RequestOptions options, String url, long modified){
    if(!Util.isEmpty(url) && url.contains(".")){
        try{
            String tail = url.substring(url.lastIndexOf(".") + 1).toLowerCase();
            String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(tail);
            options.signature(new MediaStoreSignature(type, modified, 0));
        }catch (Exception e){}
    }
}
modified改变时,Glide会将当前URL判断为新资源并且重新缓存,并不会覆盖之前的缓存记录。
也就是说如果APP中有多处地方需要显示这个图片,
那么就需要在所有显示这个图片的位置给RequestOptions指定signature属性。

.signature(new StringSignature(UUID.randomUUID().toString()))//增加签名
如果链接是文件,就用StringSignature, 
如果链接是多媒体,就用MediaStoreSignature, 

//用的此处
Glide 4.0中.signature()方法形参找不到StringSignature,而且形参改为Key。
.signature(new ObjectKey(System.currentTimeMills()))
目录
相关文章
|
XML 存储 安全
Android小提示四
Android开发一些提示
229 0
Android小提示四
|
Java 开发工具 Android开发
Android小提示三
Android开发一些提示
120 0
Android小提示三
|
XML JavaScript Java
Android小提示二
Android开发一些提示
202 0
Android小提示二
|
XML 存储 监控
Android小提示五
android开发的一些小提示
258 0
|
XML ARouter 安全
Android小提示一
Android开发一些小提示
395 0
|
4天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
3天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
14 5
|
1天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
2天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
11 3