Intent&Context&Manager&Listener

本文深入探讨了Android开发中的关键概念和技术,包括Intent数据传递、Context使用场景、Listener注册与触发、Manager服务管理等核心内容,并提供了丰富的示例代码。

Intent&Context&Listener&Manager

  1. Intent数据类型
  2. Context区别
  3. Listener
  4. Manager
01.Intent携带的数据类型
  1. 8种基本数据类型以及数组形式以及String
  2. 实现了序列化接口的对象
    1. Serializable(Sun),声明为transient 的变量不会被序列化
    2. Parcelable(Google)

public class User implements Parcelable {
  private String name;
  private int age;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  /*
   * 必须声明:public static final Parcelable.Creator<User> CREATOR反序列化的
   */
  public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
    /*
     * 用于反序列,给你一个数据包,你把数据包中的数据拿出来,封装成一个对象,并返回
     */
    public User createFromParcel(Parcel in) {
      User user = new User();
      /*
       * 注意:一定按照序列化时的顺序读取
       */
      String name = in.readString();
      int age = in.readInt();
      user.setAge(age);
      user.setName(name);
      return user;
    }
    /*
     * 如果一个对象可以被序列化,那么这个对象的数组也能被序列化
     */
    public User[] newArray(int size) {
      return new User[size];
    }
  };
  // 用于序列化对象的,将需要序列化出去的属性写到数据包中即可
  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(name);
    dest.writeInt(age);
  }
  @Override
  public int describeContents() {
    return 0;
  }
}

3. 前者序列化对象时会产生大量的临时文件,效率比较低后者效率高
02.Context的区别
  1. Activity 一个Activity对应一个Context
  2. Service 一个Service对应一个Context
  3. BroadCastReceiver中的onReceive(Context)方法执行完了了,这里的Context就完了
  4. 在内容提供者中获得上下文getContext()
  5. getApplicationContext()全局上下文
  6. 在fragment中可以通过getActivity()获得

Context

03.Listener
1. setOnItemClickListener()
2. button.setOnClickListener(OnClickListener);
3. button.setOnLongClickListener(OnClickListener);
4. checkBox.setOnCheckedChangeListener(listener);
5. listview.setOnItemClickListener(OnItemClickListener);
6. listview.setOnScrollListener(OnScrollListener);
7. imageView.setOnTouchListener()
8. fragment public void onHiddenChanged(boolean hidden) {}
9. setOnSeekBarChangeListener
10.OntouchListener
11.SeekBar.setOnSeekBarChangeListener(Listener)
04. Manager

01. smsManager

实现:发送短信


SmsManager smsManager = SmsManager.getDefault();
//发送短信是通过API 提供的短信管理器实现的
//通过SmsManager 的静态方法获取对象
SmsManager smsManager = SmsManager.getDefault();
//短信长度超过一定的限制后需要切割成多条分批发送
//一定要使用SmsManager 对象提供的divideMessage(String)方法切割
ArrayList<String> parts = smsManager.divideMessage(sms);
smsManager.sendMultipartTextMessage(num, null, parts, null, null);

02. TelephoneManager

实现:监听电话状态


TelephonyManager tm = (TelephonyManager) context.getSystemServer(Context.TELEPHONY_SERVICE);
//电话状态的监听
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
//SIM卡的绑定:权限:android.permission.READ_PHONE_STATE
String simSerialNumber = tm.getSimSerialNumber();

03. connectivityManager
实现:获取网络状态


ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

04. WindowManager

实现:获取屏幕的宽高


// 方式1:获取屏幕的宽高
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
//方式2: Activity中获取屏幕的宽高,
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
//方式3:推荐该方式.
DisplayMetrics metrics =getWindowManager().getDefaultDisplay().getDisplayMetrics();
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;

05. FragmentManager


FragmentManager fragmentManager = getSupportFragmentManager();

06. LocationManager GPS
实现:获取GPS位置服务


LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
String provider = LocationManager.GPS_PROVIDER;

long minTime = 0;
float minDistance = 0;
lm.requestLocationUpdates(provider, minTime, minDistance, this);
public void onLocationChanged(Location location) {
    // 经度
    double longitude = location.getLongitude();
    // 纬度
    double latitude = location.getLatitude();
    System.out.println(
            "onLocationChanged:" + ",longitude:" + longitude + ",latitude:" + latitude);
}

protected void onPause() {
    super.onPause();
    // 取消监听, 节约资源
    lm.removeUpdates(this);
}

07. DevicePolicyManager

实现:获取设备管理员权限,锁屏,擦除数据


DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);

如用模拟器,请使用5.0以下版本测试一键锁屏

  • 实现 : 参考/docs/guide/topics/admin/device-admin.html页面

1. 创建一个DeviceAdminReceiver 的子类, 例如LockDeviceAdminReceiver

2. 在manifest文件中注册这个新创建的广播接收者,模板代码
    <receiver
        android:name="com.itheima.lockapp.LockDeviceAdminReceiver"
        android:description="@string/device_admin_description" // 本功能的描述, 需自己创建
        android:label="@string/app_name" // 软件名称
        android:permission="android.permission.BIND_DEVICE_ADMIN" >
        <meta-data
            android:name="android.app.device_admin"
            android:resource="@xml/device_admin" /> // 该文件用来声明本软件所要使用的安全策略, 需自己创建文件
        <intent-filter>
            <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
        </intent-filter>
    </receiver>

>
3. 在res目录下, 新建一个目录,名为xml, 在xml目录下新建一个xml文件, 文件名必须和manifest文件中声明的receiver的android:resource节点值一致. 文件内容如下, 需根据实际业务需要进行增删




















>
4. 实现功能, 监听状态
public class MainActivity extends Activity {
private static final int REQUEST_CODE_ENABLE_ADMIN = 100;
private DevicePolicyManager dpm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取设备策略管理器
dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
// 创建自定义Receiver的唯一标识
ComponentName admin = new ComponentName(this, LockDeviceAdminReceiver.class);
// 判断自定义的Receiver是否已经被激活
boolean isAdaminActive = dpm.isAdminActive(admin);
// 如果已经被激活,直接锁屏并关闭当前页面
if (isAdaminActive) {
dpm.lockNow();
finish();
} else {
// 如果没有被激活,弹窗提示用户去激活系统管理员
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
getString(R.string.device_admin_description));
startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_ENABLE_ADMIN) {
// 激活成功, 锁屏并关闭当前页面
if (resultCode == Activity.RESULT_OK) {
dpm.lockNow();
finish();
// 激活失败, 直接退出
} else if (resultCode == Activity.RESULT_CANCELED) {
finish();
}
}
}
}

* 需求 : 激活系统管理员以后直接卸载程序, 不弹出警告窗口
* 实现 : 判断当前软件是否已经激活系统管理员, 如果激活了, 先取消. 之后调用隐式意图卸载程序
* 代码 : 

public class UninstallActivity extends Activity {
    private DevicePolicyManager dpm;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_uninstall);
        // 获取设备策略管理器
        dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
        // 创建自定义Receiver的唯一标识
        ComponentName admin = new ComponentName(this, LockDeviceAdminReceiver.class);
        // 判断自定义的Receiver是否已经被激活
        boolean isAdaminActive = dpm.isAdminActive(admin);
        // 如果激活了, 先取消设备管理器
        if (isAdaminActive) {
            dpm.removeActiveAdmin(admin);
        }
        // 发送隐式意图,卸载当前应用
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_DELETE);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivity(intent);
        finish();
    }
}
// manifest文件
<activity
    android:name=".UninstallActivity"
    android:label="一键卸载"
    android:launchMode="singleInstance" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

* 需求 : 实现远程擦除数据和锁屏的功能
* 实现 : 通过DevicePolicyManager的wipeData()方法和lockNow()实现
* 代码 :

DevicePolicyManager dpm = (DevicePolicyManager) context
        .getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
abortBroadcast();
DevicePolicyManager dpm = (DevicePolicyManager) context
        .getSystemService(Context.DEVICE_POLICY_SERVICE);
//设置密码.
dpm.resetPassword("123", DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY);

08. ActivityManager

实现:查询当前运行的服务,正在运行的进程,内存使用情况,杀死进程


ActivityManager am = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE);
//获取服务的状态
public static boolean isServiceRunning(Context context,
        Class<? extends Service> clazz) {
    boolean flag = false;
    // 获取ActivityManager
    ActivityManager am = (ActivityManager) context
            .getSystemService(Context.ACTIVITY_SERVICE);
    // 获取正在运行的服务
    List<RunningServiceInfo> lis = am.getRunningServices(Integer.MAX_VALUE);
    // 遍历集合
    for (RunningServiceInfo info : lis) {
        // 获取服务的名字
        String className = info.service.getClassName();
        // 如果有服务和我们的服务名字一致, 说明正在运行
        if (className.equals(clazz.getName())) {
            flag = true;
        }
    }
    return flag;
}


**不能在Android5.0以上机器使用以下代码**
* 正在运行的进程可以通过ActivityManager.getRunningAppProcesses()方法获得

* 内存使用情况可以通过ActivityManager.getMemoryInfo()方法获取

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
// 获取总共可运行内存个数
PackageManager pm = getPackageManager();

## 0902_版本适配获得内存信息
* 需求 :  判断当前系统的版本, 对于低版本系统使用读取系统文件的方式获取总内存大小
* 实现 : * 读取系统的/proc/meminfo文件获取内存信息
private void initRam() {
    // 获取内存信息
    MemoryInfo outInfo = new MemoryInfo();
    am.getMemoryInfo(outInfo);
    //可用内存
    long availMem = outInfo.availMem;
    long totalMem = 0;
    int sdkInt = Build.VERSION.SDK_INT;
    // 高版本系统,直接读取
    if (sdkInt >= Build.VERSION_CODES.JELLY_BEAN) {
        totalMem = outInfo.totalMem;
    } else {
        // 低版本系统读取系统文件
        File file = new File("/proc/meminfo");
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(file));
            String readLine = br.readLine();
            readLine = readLine.replace("MemTotal:", "");
            readLine = readLine.replace("kB", "");
            readLine = readLine.trim();
            totalMem = Long.valueOf(readLine) * 1024;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(br);
        }

    }
//已用内存
long usedMem = totalMem - availMem;
//
private void initAdapter() {
    ArrayList<AppRAMBean> list = new ArrayList<AppRAMBean>();
    // 遍历所有正在运行的进程
    for (RunningAppProcessInfo info : runningAppProcesses) {
        AppRAMBean bean = new AppRAMBean();
        // 获取包名
        String pkgName = info.processName;
        // 获取应用图标.如果有就用应用自己的,没有就用默认的
        try {
            Drawable icon = packageManager.getApplicationIcon(pkgName);
            bean.icon = icon;
        } catch (NameNotFoundException e) {
            bean.icon = getResources().getDrawable(R.drawable.ic_launcher);
            e.printStackTrace();
        }

        try {
            ApplicationInfo applicationInfo = packageManager.getApplicationInfo(pkgName, 0);
            // 获取应用的名称
            CharSequence applicationLabel = packageManager.getApplicationLabel(applicationInfo);
            bean.name = applicationLabel.toString();
            // 获取是否是系统应用
            int flag = applicationInfo.flags;
            if ((flag & ApplicationInfo.FLAG_SYSTEM) == ApplicationInfo.FLAG_SYSTEM) {
                bean.isSystem = true;
            } else {
                bean.isSystem = false;
            }
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        // 获取当前进程所占用的内存信息
        int pid = info.pid;
        android.os.Debug.MemoryInfo processMemoryInfo =
                activityManager.getProcessMemoryInfo(new int[] {pid})[0];
        int totalPss = processMemoryInfo.getTotalPss();
        bean.usedRam = totalPss*1024
    }
}

* 实现 : 清理进程的方法 ActivityManager.killBackgroundProcesses(String pkgName). 
* 杀死后台进程要添加权限 android.permission.KILL_BACKGROUND_PROCESSES

09. AssetsManager 获取资产目录路径


getAssets

10. PackageManager

实现:版本信息,应用信息,包名,总进程数

  • 1.获取版本信息,应用的信息:名称,图标,安装路径,包名,UID(获取流量).2.判断安装位置.判断系统应用,
  • 3.通过包名,打开程序,卸载程序,打开应用详情页面.4.通过文件的路径,可以跳转安装程序页面.

PackageManager pm = context.getPackageManager();

// 获取当前包的版本号,可用于升级.
PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
String versionName = packageInfo.versionName;

// 获取当前手机安装的所有应用信息
List<ApplicationInfo> list = pm.getInstalledApplications(0);
for (ApplicationInfo info : list) {
    // 获取应用的名称
    CharSequence applicationLabel = pm.getApplicationLabel(info);

    // 获取应用的图标
    Drawable icon = pm.getApplicationIcon(info);

    // 获取应用的安装路径
    String sourceDir = info.sourceDir;
    File file = new File(sourceDir);
    // 获取包名
    bean.pkgName = info.packageName;

    // 获去应用的uid,可用于统计流量
    int uid = info.uid;

    // 获取应用的大小
    long totalSpace = file.length();
    bean.size = Formatter.formatFileSize(this, totalSpace);

    // 判断应用的安装位置
    if (sourceDir.startsWith("/mnt/asec")) {
        bean.isOnSD = true;
    } else {
        bean.isOnSD = false;
    }
}

//判断出程序是否是系统程序
// 方法一 : 判断ApplicationInfo.sourceDir 是否以"/system" 开头
if (sourceDir.startsWith("/system")) {
    bean.isSystemApp = true;
} else {
    bean.isSystemApp = false;
}

//方法二 : 判断ApplicationInfo.FLAG_SYSTEM与运算的结果
int flags = info.flags;

if ((flags & ApplicationInfo.FLAG_SYSTEM) == ApplicationInfo.FLAG_SYSTEM) {
    bean.isSystemApp = true;
} else {
    bean.isSystemApp = false;
}

// 跳转应用信息详情界面,包名
 Intent intent = new Intent();
 intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
 intent.addCategory("android.intent.category.DEFAULT");
 intent.setData(Uri.parse("package:" + itemBean.pkgName));
 startActivity(intent);

//打开程序,包名
intent = getPackageManager().getLaunchIntentForPackage(itemBean.pkgName);
startActivity(intent); 

//安装程序,文件的目录
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.parse("file:" + file.getAbsolutePath()),
        "application/vnd.android.package-archive");
startActivityForResult(intent, REQ_CODE_INSTALL_APP);

// 卸载应用,包名
Uri packageURI = Uri.parse("package:" + itemBean.pkgName);
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
startActivity(uninstallIntent);

// 注册广播,拿到卸载应用的包名
receiver = new UninstallReceiver();
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
registerReceiver(receiver, filter);
// 广播类
class UninstallReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //获得广播的内容,package:+ 包名
        String dataString = intent.getDataString();
        //拿到包名
        dataString = dataString.replace("package:", "");
    }
}
  • 需求 : 获取流量使用的详细数据. 此功能只能在低版本手机上测试,不能使用模拟器
  • 实现 :
    • 默认情况下,每一个应用的流量使用情况都会储存在”/proc/uid_stat/uid/”目录下的两个文件中,tcp_rcv文件记录收到的流量,tcp_snd文件记录发送的流量.此方法获取的数据比较准确,但是在高版本手机上无法读取到这两个文件.在改版的手机上因为目录可能被更改,也会导致无法使用
    • 通过TrafficStats.getUidRxBytes获取收到的流量,通过TrafficStats.getUidTxBytes获取发送的流量,但是这种方法获取的数据并不准确

PackageManager pm = getPackageManager();
List<ApplicationInfo> lists = pm.getInstalledApplications(0);
for (ApplicationInfo info : lists) {
    //获取应用的标识符uid
    int uid = info.uid;
    // 此方法获取的数据并不准确
    long uidRxBytes = TrafficStats.getUidRxBytes(uid);
    long uidTxBytes = TrafficStats.getUidTxBytes(uid);

// 此方法比较准确,但是在高版本手机上无法使用.
// 在改版的手机上因为目录可能被更改,也会导致无法使用
private long getReceive(int uid) {
    //收到的流量
    File file = new File("/proc/uid_stat/" + uid + "/tcp_rcv");
    //发送的流量
    //File file = new File("/proc/uid_stat/" + uid + "/tcp_snd");
    BufferedReader br = null;
    try {
        br = new BufferedReader(new FileReader(file));
        String readLine = br.readLine();
        return Long.valueOf(readLine);
    } catch (Exception e) {
        e.printStackTrace();
        return 0;
    } finally {
        if (br != null) {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            br = null;
        }
    }


**不能在Android5.0以上机器使用以下代码**
* 总进程数可以通过PackageManager.getInstalledPackages(0)方法的返回值获取
// 获取手机上所有已安装的应用
List<PackageInfo> installedPackages = pm.getInstalledPackages(0);
// 创建集合
Set<String> set = new HashSet<String>();
for (PackageInfo packageInfo : installedPackages) {
    // 获取所有Application节点的processName
    String processName = packageInfo.applicationInfo.processName;
    set.add(processName);
    // 获取所有Activity节点的processName
    ActivityInfo[] activities = packageInfo.activities;
    if (activities != null) {
        for (ActivityInfo activityInfo : activities) {
            String processName2 = activityInfo.processName;
            set.add(processName2);
        }
    }
    // 获取所有Service节点的processName
    ServiceInfo[] services = packageInfo.services;
    if (services != null) {
        for (ServiceInfo serviceInfo : services) {
            set.add(serviceInfo.processName);
        }
    }
    // 获取所有receiver节点的processName
    ActivityInfo[] receivers = packageInfo.receivers;
    if (receivers != null) {
        for (ActivityInfo activityInfo : receivers) {
            set.add(activityInfo.processName);
        }
    }
    // 获取所有Provider节点的processName
    ProviderInfo[] providers = packageInfo.providers;
    if (providers != null) {
        for (ProviderInfo providerInfo : providers) {
            set.add(providerInfo.processName);
        }
    }
    ssv_num.setFreeText("可运行" + set.size() + "个");
}
// BroadcastManager.java package com.xia.managementtoolbox.utils; import android.app.Application; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.util.Log; import androidx.annotation.MainThread; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleEventObserver; import androidx.lifecycle.LifecycleOwner; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class BroadcastManager implements LifecycleEventObserver { private final Context context; private static BroadcastManager instance; // 统一记录:每个 BroadcastReceiver 对应的 filter 和 owner private final Map<BroadcastReceiver, ReceiverRecord> receiverRecords = new HashMap<>(); /** * 内部类:封装广播接收器的相关信息 */ private static class ReceiverRecord { final IntentFilter filter; final LifecycleOwner owner; ReceiverRecord(IntentFilter filter, LifecycleOwner owner) { this.filter = filter; this.owner = owner; } } /** * 私有构造,单例模式 */ private BroadcastManager(Context context) { this.context = context.getApplicationContext(); // 使用 Application Context 防止泄漏 } /** * 获取单例实例 */ public static synchronized BroadcastManager getInstance(Context context) { if (instance == null) { instance = new BroadcastManager(context); } return instance; } /** * 注册广播接收器并绑定生命周期 */ @MainThread public void register(BroadcastReceiver receiver, IntentFilter filter, LifecycleOwner owner) { if (receiver == null || filter == null || owner == null) return; // 先解注册同个 receiver(防止重复注册崩溃) unregister(receiver); try { ContextCompat.registerReceiver(context, receiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED); receiverRecords.put(receiver, new ReceiverRecord(filter,owner)); owner.getLifecycle().addObserver(this); } catch (Exception e) { Log.e("错误",e.toString()); } } /** * 手动解注册某个 receiver */ public void unregister(BroadcastReceiver receiver) { if (receiver != null && receiverRecords.containsKey(receiver)) { try { context.unregisterReceiver(receiver); } catch (IllegalArgumentException e) { // 已经被解注册了,忽略 } finally { receiverRecords.remove(receiver); } } } /** * 发送应用内广播(可用于 Service → Activity 通信) */ public void sendInternalBroadcast(Intent intent) { intent.setPackage(context.getPackageName()); // 限定本应用 context.sendBroadcast(intent); } /** * 生命周期回调:在宿主销毁时自动解注册 */ @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event == Lifecycle.Event.ON_DESTROY) { Iterator<Map.Entry<BroadcastReceiver, ReceiverRecord>> it = receiverRecords.entrySet().iterator(); while (it.hasNext()) { Map.Entry<BroadcastReceiver, ReceiverRecord> entry = it.next(); if (entry.getValue().owner == source) { BroadcastReceiver receiver = entry.getKey(); unregister(receiver); // 安全解注册 it.remove(); // 从集合中移除 } } source.getLifecycle().removeObserver(this); } } // ======================================== // 🔧 静态便捷方法(对外暴露常用动作) // ======================================== /** * 监听外部存储挂载状态变化 */ public static void observeStorageMount(LifecycleOwner owner, BroadcastReceiver receiver) { Context appContext = owner instanceof Context ? (Context) owner : null; if (appContext == null) return; Application application = (Application) appContext.getApplicationContext(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_MOUNTED); filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); filter.addDataScheme("file"); getInstance(application).register(receiver, filter, owner); } /** * 监听存储空间不足警告 */ public static void observeStorageLow(LifecycleOwner owner, BroadcastReceiver receiver) { Context appContext = owner instanceof Context ? (Context) owner : null; if (appContext == null) return; Application application = (Application) appContext.getApplicationContext(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW); filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); getInstance(application).register(receiver, filter, owner); } /** * 注册应用内事件监听 */ public static void observeDownloadComplete(LifecycleOwner owner, BroadcastReceiver receiver) { Context appContext = owner instanceof Context ? (Context) owner : null; if (appContext == null) return; Application application = (Application) appContext.getApplicationContext(); IntentFilter filter = new IntentFilter("DOWNLOAD_COMPLETED"); getInstance(application).register(receiver, filter, owner); } /** * Service 完成任务后通知 UI 更新 */ public static void notifyDownloadCompleted(Context ctx, String filePath) { Intent intent = new Intent("DOWNLOAD_COMPLETED"); intent.putExtra("file_path", filePath); getInstance(ctx).sendInternalBroadcast(intent); } } package com.xia.managementtoolbox; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.util.Log; import androidx.core.app.NotificationCompat; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; public class FileCopyService extends Service { private static final String CHANNEL_ID = "FileCopyChannel"; private static final int NOTIFICATION_ID = 1; private HandlerThread handlerThread; private Handler backgroundHandler; private ProgressCallback progressCallback; // Binder 类,用于 Activity 获取 Service 实例 public class LocalBinder extends Binder { public FileCopyService getService() { return FileCopyService.this; } } private final IBinder binder = new LocalBinder(); @Override public void onCreate() { super.onCreate(); // 创建后台线程处理 I/O 操作 handlerThread = new HandlerThread("FileCopyWorker"); handlerThread.start(); backgroundHandler = new Handler(handlerThread.getLooper()); createNotificationChannel(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 如果通过 startService 启动,也转为前台服务 startForeground(NOTIFICATION_ID, buildNotification(0)); return START_NOT_STICKY; } @Override public IBinder onBind(Intent intent) { return binder; } @Override public boolean onUnbind(Intent intent) { // 可选:当所有客户端断开连接后停止服务 return super.onUnbind(intent); } @Override public void onDestroy() { if (handlerThread != null) { handlerThread.quitSafely(); } super.onDestroy(); } // 创建通知渠道 private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( CHANNEL_ID, "文件复制服务", NotificationManager.IMPORTANCE_LOW ); channel.setDescription("显示文件复制进度"); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } } // 构建通知 private Notification buildNotification(int progress) { return new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("文件复制中...") .setContentText(progress + "%") .setSmallIcon(android.R.drawable.ic_menu_upload) .setOngoing(true) .setProgress(100, progress, false) .build(); } // 执行文件复制任务(由 Activity 调用) public void startCopy(File srcFile, File destFile, ProgressCallback callback) { this.progressCallback = callback; // 提交到线程池执行 backgroundHandler.post(() -> { try { long totalSize = srcFile.length(); long copied = 0; FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel(); byte[] buffer = new byte[8192]; int read; while ((read = fis.read(buffer)) != -1) { fos.write(buffer, 0, read); copied += read; int progress = (int) ((copied * 100) / totalSize); // 更新通知和回调 updateNotification(progress); if (progressCallback != null) { progressCallback.onProgress(progress); } } progressCallback.onComplete(); // // 模拟测试 // new Thread(()->{ // for(int i=1;i<=100;i++){ // updateNotification(i); // progressCallback.onProgress(i); // try { // Thread.sleep(200); // } catch (InterruptedException e) { // throw new RuntimeException(e); // } // } // progressCallback.onComplete(); // }).start(); inChannel.close(); outChannel.close(); fis.close(); fos.close(); // 完成后移除通知和服务 stopForeground(true); stopSelf(); } catch (IOException e) { Log.e("E",e.toString()); if (progressCallback != null) { progressCallback.onError(e.getMessage()); } } }); } // 通知更新接口 private void updateNotification(int progress) { Notification notification = buildNotification(progress); NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); nm.notify(NOTIFICATION_ID, notification); } // 进度回调接口 public interface ProgressCallback { void onProgress(int progress); void onError(String error); void onComplete(); } } package com.xia.managementtoolbox; import android.content.Intent; import android.content.SharedPreferences; import android.icu.text.DecimalFormat; import android.icu.text.SimpleDateFormat; import android.os.Bundle; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import androidx.activity.OnBackPressedCallback; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import java.io.File; import java.util.Date; import java.util.Locale; public class FileDetailActivity extends AppCompatActivity { private EditText edText; private String file_name; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.file); Intent intent = getIntent(); String filePath = intent.getStringExtra("file_path"); if (filePath == null || filePath.isEmpty()) { Toast.makeText(this, "文件信息无效", Toast.LENGTH_SHORT).show(); finish(); return; } File file = new File(filePath); TextView tvName = findViewById(R.id.tv_file_name); TextView tvPath = findViewById(R.id.tv_file_path); TextView tvSize = findViewById(R.id.tv_file_size); TextView tvTime = findViewById(R.id.tv_last_time); edText = findViewById(R.id.editText); tvName.setText(file.getName()); tvSize.setText(formatFileSize(file.length())); tvPath.setText(file.getAbsolutePath()); tvTime.setText( new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) .format(new Date(file.lastModified())) ); file_name = file.getName(); // 恢复之前保存的文本 SharedPreferences sp = getSharedPreferences("user_input_store", MODE_PRIVATE); String savedText = sp.getString(file_name + "saved_text", ""); edText.setText(savedText); edText.setSelection(edText.length()); getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { saveDataAndFinish(); } }); } private void saveDataAndFinish() { // 获取输入内容 String userInput = edText.getText().toString(); // 保存到 SharedPreferences SharedPreferences sp = getSharedPreferences("user_input_store", MODE_PRIVATE); sp.edit().putString(file_name + "saved_text", userInput).apply(); // 设置返回数据 Intent data = new Intent(); data.putExtra("input", userInput); setResult(RESULT_OK, data); finish(); } private String formatFileSize(long size) { if (size <= 0) return "0 B"; final String[] units = {"B", "KB", "MB", "GB", "TB"}; int digitGroups = (int) (Math.log(size) / Math.log(1024)); return new DecimalFormat("#,##0.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups]; } } package com.xia.managementtoolbox; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import androidx.activity.result.ActivityResult; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.xia.managementtoolbox.utils.BroadcastManager; import java.io.File; import java.util.ArrayList; import java.util.List; public class FileListFragment extends Fragment { private FileAdapter fileAdapter; private List<File> fileList; private ActivityResultLauncher<Intent> startForResult; private TextView resultTextView; private ServiceListener mListener; private final BroadcastReceiver storageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, @NonNull Intent intent) { String action = intent.getAction(); if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) { Toast.makeText(context, "SD卡已挂载", Toast.LENGTH_SHORT).show(); loadFiles(); } else if (Intent.ACTION_MEDIA_UNMOUNTED.equals(action)) { Toast.makeText(context, "SD卡已移除", Toast.LENGTH_SHORT).show(); } } }; private final BroadcastReceiver downloadReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, @NonNull Intent intent) { if ("DOWNLOAD_COMPLETED".equals(intent.getAction())) { Toast.makeText(context, "新文件已下载完成!", Toast.LENGTH_SHORT).show(); loadFiles(); // 刷新列表 } } }; @Override public void onAttach(@NonNull Context context) { super.onAttach(context); // 确保宿主 Activity 实现了该接口 if (context instanceof ServiceListener) { mListener = (ServiceListener) context; } else { throw new RuntimeException(context + " 必须实现 OnFragmentInteractionListener"); } } @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_file_list, container, false); RecyclerView recyclerView = view.findViewById(R.id.recyclerView); resultTextView = view.findViewById(R.id.result); // 监听 SD 卡挂载 BroadcastManager.observeStorageMount(this, storageReceiver); // 监听下载完成广播 BroadcastManager.observeDownloadComplete(this, downloadReceiver); // 初始化数据 fileList = new ArrayList<>(); fileAdapter = new FileAdapter(fileList, new FileAdapter.OnFileClickListener() { @Override public void onDetailClick(File file) { Intent intent = new Intent(requireContext(), FileDetailActivity.class); intent.putExtra("file_path", file.getAbsolutePath()); startForResult.launch(intent); } @Override public void onDownloadClick(File file){ if(mListener !=null){ mListener.bindAndStartService(file); } } @Override public void onDeleteClick(File file, int position) { if (file.delete()) { fileList.remove(position); fileAdapter.notifyItemRemoved(position); Toast.makeText(requireContext(), file.getName() + " 已删除", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(requireContext(), "删除失败", Toast.LENGTH_SHORT).show(); } } }); recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); recyclerView.setAdapter(fileAdapter); // 提前注册 launcher(最好在 onCreate 中注册更安全) startForResult = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), this::handleActivityResult ); return view; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); loadFiles(); // 数据加载移到 onViewCreated } /** * 处理返回结果(安全判空) */ @SuppressLint("SetTextI18n") private void handleActivityResult(@NonNull ActivityResult result) { if (!isAdded() || getView() == null) return; if (result.getResultCode() == Activity.RESULT_OK) { Intent data = result.getData(); if (data != null && data.hasExtra("input")) { String text = data.getStringExtra("input"); if (text != null && !text.trim().isEmpty()) { resultTextView.setText("收到返回值: " + text); return; } } } resultTextView.setText("无返回结果"); } /** * 加载文件列表 */ private void loadFiles() { File dir = requireContext().getFilesDir(); FileScanner.scanFilesAsync(dir, new FileScanner.ScanCallback() { @SuppressLint("NotifyDataSetChanged") @Override public void onSuccess(List<File> files) { if (isAdded() && getView() != null) { fileList.clear(); fileList.addAll(files); fileAdapter.notifyDataSetChanged(); } } @Override public void onError(Exception e) { Toast.makeText(requireContext(), "扫描失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } }); } } class FileAdapter extends RecyclerView.Adapter<FileAdapter.ViewHolder> { public interface OnFileClickListener { void onDetailClick(File file); void onDownloadClick(File file); void onDeleteClick(File file, int position); } private final List<File> files; private final OnFileClickListener listener; public FileAdapter(List<File> files, OnFileClickListener listener) { this.files = files; this.listener = listener; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(android.R.layout.simple_list_item_1, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { File file = files.get(position); holder.textView.setText(file.getName()); holder.itemView.setOnLongClickListener(v -> { new AlertDialog.Builder(v.getContext()) .setTitle("选择操作") .setItems(new String[]{"查看详情", "下载文件", "删除文件"}, (dialog, which) -> { switch (which) { case 0: listener.onDetailClick(file); break; case 1: listener.onDownloadClick(file); break; case 2: listener.onDeleteClick(file, position); break; } }) .setNegativeButton("取消", null) .show(); return true; }); } @Override public int getItemCount() { return files.size(); } static class ViewHolder extends RecyclerView.ViewHolder { TextView textView; ViewHolder(View itemView) { super(itemView); textView = itemView.findViewById(android.R.id.text1); } } } package com.xia.managementtoolbox; import android.os.Handler; import android.os.Looper; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public class FileScanner { public interface ScanCallback { void onSuccess(List<File> files); void onError(Exception e); } /** * 异步扫描指定目录下的文件 */ public static void scanFilesAsync(File directory, ScanCallback callback) { new Thread(() -> { try { if (!directory.exists() || !directory.isDirectory()) { callback.onSuccess(Collections.emptyList()); return; } File[] files = directory.listFiles(); List<File> result = new ArrayList<>(); if (files != null) { Arrays.sort(files, (f1, f2) -> f1.getName().compareToIgnoreCase(f2.getName())); Collections.addAll(result, files); } // 回到主线程回调 Handler mainHandler = new Handler(Looper.getMainLooper()); mainHandler.post(() -> callback.onSuccess(result)); } catch (Exception e) { Handler mainHandler = new Handler(Looper.getMainLooper()); mainHandler.post(() -> callback.onError(e)); } }).start(); } } package com.xia.managementtoolbox; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.viewpager2.adapter.FragmentStateAdapter; import androidx.viewpager2.widget.ViewPager2; import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayoutMediator; import com.xia.managementtoolbox.utils.BroadcastManager; import java.io.File; public class MainActivity extends AppCompatActivity implements ServiceListener{ private FileCopyService fileCopyService; private boolean isBound = false; private File src; private File dest; private TextView progressText; private final ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { FileCopyService.LocalBinder binder = (FileCopyService.LocalBinder) service; fileCopyService = binder.getService(); isBound = true; startCopyOperation(); } @Override public void onServiceDisconnected(ComponentName name) { isBound = false; } }; private BroadcastReceiver storageReceiver; static class ViewPagerAdapter extends FragmentStateAdapter { public ViewPagerAdapter(FragmentActivity fa) { super(fa); } @NonNull @Override public Fragment createFragment(int position) { return position == 0 ? new FileListFragment() : new SettingsFragment(); } @Override public int getItemCount() { return 2; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager2 viewPager = findViewById(R.id.viewPager); TabLayout tabLayout = findViewById(R.id.tabLayout); progressText = findViewById(R.id.result); // 初始化广播接收器 registerStorageReceiver(); // 设置适配器 ViewPagerAdapter adapter = new ViewPagerAdapter(this); viewPager.setAdapter(adapter); // 绑定 TabLayout 与 ViewPager2 new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(position == 0 ? "文件列表" : "设置") ).attach(); } @Override public void bindAndStartService(@NonNull File file) { src = file; dest = new File(getExternalFilesDir(null), file.getName()+"(1)"); Intent serviceIntent = new Intent(this, FileCopyService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); // 先启动前台服务 } bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindServiceIfNeeded(); // 防止内存泄漏:必须反注册 if (storageReceiver != null) { try { unregisterReceiver(storageReceiver); } catch (IllegalArgumentException e) { // 接收器未注册时可能抛出异常,忽略即可 } storageReceiver = null; } super.onDestroy(); } private void startCopyOperation() { if (fileCopyService != null) { fileCopyService.startCopy(src, dest, new FileCopyService.ProgressCallback() { @SuppressLint("SetTextI18n") @Override public void onProgress(int progress) { runOnUiThread(() -> progressText.setText("进度: " + progress + "%")); } @Override public void onError(String error) { runOnUiThread(() -> { Toast.makeText(MainActivity.this, "错误: " + error, Toast.LENGTH_SHORT).show(); unbindServiceIfNeeded(); }); } @Override public void onComplete() { Toast.makeText(MainActivity.this, "复制完成!", Toast.LENGTH_SHORT).show(); // 在这里发送广播,通知其他组件 BroadcastManager.notifyDownloadCompleted(MainActivity.this,dest.getAbsolutePath()); } }); } } private void unbindServiceIfNeeded() { if (isBound) { unbindService(serviceConnection); isBound = false; } } private void registerStorageReceiver() { storageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) { Toast.makeText(context, "SD卡已挂载", Toast.LENGTH_SHORT).show(); } else if (Intent.ACTION_MEDIA_UNMOUNTED.equals(action)) { Toast.makeText(context, "SD卡已卸载", Toast.LENGTH_SHORT).show(); } else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) { Toast.makeText(context, "设备存储空间不足!", Toast.LENGTH_LONG).show(); } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) { Toast.makeText(context, "存储空间恢复正常", Toast.LENGTH_SHORT).show(); } } }; // 创建 IntentFilter 并添加要监听的动作 IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_MOUNTED); filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW); filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); // 注意:对于 MEDIA_UNMOUNTED 等文件系统事件,需要添加 data scheme filter.addDataScheme("file"); // 注册广播接收器 registerReceiver(storageReceiver, filter); } } package com.xia.managementtoolbox; import java.io.File; public interface ServiceListener { void bindAndStartService(File file); } 检查一下代码的程序设计问题,不需要优化,找出错误即可,编译过程很长
最新发布
12-31
package com.isa.navi.library.manager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Log; import androidx.annotation.GuardedBy; import com.isa.navi.library.IISANaviProxy; import com.isa.navi.library.constant.Const; import com.isa.navi.library.map.MapProxy; import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * @author haoj * @description description * @date 2023-06-20 */ public class ISANaviManager { public static final String TAG = Const.ISA_NAVI + "ServiceManager"; private static final int MSG_MANAGER_INIT = 0; private static final int MSG_CONNECT_RETRY = 1; private static final int MSG_CONNECT_FAIL = 2; private static final int MSG_SERVICE_STATUS = 3; private Context mContext; private Handler mWorkHandler; private HandlerThread mHandlerThread = null; private final ServiceConnection mServiceConnectionListener; @GuardedBy("this") private int mConnectionRetryCount; @GuardedBy("this") private IISANaviProxy mService; @GuardedBy("this") private IBinder mBinder; private IBinder.DeathRecipient mDeathRecipient; private boolean mIsInit = false; private List<IServiceStatusChangeListener> mServiceStatusListeners; private volatile static ISANaviManager mInstance; public static ISANaviManager getInstance() { if (mInstance == null) { synchronized (ISANaviManager.class) { if (mInstance == null) { mInstance = new ISANaviManager(); } } } return mInstance; } private ISANaviManager() { Log.d(TAG, "constructor"); initHandler(); mDeathRecipient = new DeathRecipient(); mServiceStatusListeners = new CopyOnWriteArrayList<>(); mServiceConnectionListener = new ServiceConnectionListener(); MapProxy.getInstance().initServiceManager(this); } public void initialize(Context context) { Log.d(TAG, "initialize:" + mIsInit + " ,getPackageName:" + context.getPackageName()); if (!mIsInit) { mContext = context.getApplicationContext(); if (!mWorkHandler.hasMessages(MSG_MANAGER_INIT)) { mWorkHandler.removeMessages(MSG_MANAGER_INIT); } mWorkHandler.sendEmptyMessage(MSG_MANAGER_INIT); mIsInit = true; } } private void handleMessage(Message msg) { Log.d(TAG, "handleMessage msg:" + msg.what); switch (msg.what) { case MSG_MANAGER_INIT: case MSG_CONNECT_RETRY: startService(); break; case MSG_CONNECT_FAIL: handleReconnect(); break; case MSG_SERVICE_STATUS: boolean isConnect = (boolean) msg.obj; if (isConnect) { MapProxy.getInstance().initialize(); } notifyServiceStatusChange(isConnect); break; } } class DeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { Log.d(TAG, "binderDied:"); if (mBinder != null) { mBinder.unlinkToDeath(this, 0); } mBinder = null; handleRemoteException(); sendServiceStatusMessage(false); } } class ServiceConnectionListener implements ServiceConnection { public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected name:" + name); try { mBinder = service; mBinder.linkToDeath(mDeathRecipient, 0); mService = IISANaviProxy.Stub.asInterface(service); sendServiceStatusMessage(true); } catch (RemoteException e) { e.printStackTrace(); } } public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected name: " + name); mBinder = null; handleRemoteException(); sendServiceStatusMessage(false); } } private void sendServiceStatusMessage(boolean isConnect) { if (mWorkHandler.hasMessages(MSG_SERVICE_STATUS)) { mWorkHandler.removeMessages(MSG_SERVICE_STATUS); } Message msg = Message.obtain(); msg.what = MSG_SERVICE_STATUS; msg.obj = isConnect; mWorkHandler.sendMessage(msg); } private void startService() { Intent intent = new Intent(); intent.setComponent(new ComponentName(Const.SVR_PACKAGE_NAME, Const.SVR_SERVICE_NAME)); intent.setAction(Const.SVR_ACTION_NAME); Log.d(TAG, "startService: =========>" + mContext.getPackageName()); boolean bound = mContext.bindService(intent, mServiceConnectionListener, Context.BIND_AUTO_CREATE); Log.d(TAG, "startService bound:" + bound); if (!bound) { ++mConnectionRetryCount; if (mConnectionRetryCount > 20) { Log.d(TAG, "startService cannot bind to privacy service after max retry"); if (!mWorkHandler.hasMessages(MSG_CONNECT_RETRY)) { mWorkHandler.sendEmptyMessage(MSG_CONNECT_FAIL); } } else { if (!mWorkHandler.hasMessages(MSG_CONNECT_RETRY)) { mWorkHandler.sendEmptyMessageDelayed(MSG_CONNECT_RETRY, 500L); Log.d(TAG, "startService bindService fail retry"); } } } else { mConnectionRetryCount = 0; mWorkHandler.removeMessages(MSG_CONNECT_FAIL); mWorkHandler.removeMessages(MSG_CONNECT_RETRY); Log.d(TAG, "startService bindService success"); } } private synchronized IISANaviProxy getService() { Log.d(TAG, "getIProxyThrow mService:" + mService); synchronized (ISANaviManager.class) { if (mService == null) { startService(); } } return mService; } private void handleRemoteException() { Log.d(TAG, "handleRemoteException: "); if (!mWorkHandler.hasMessages(MSG_CONNECT_FAIL)) { mWorkHandler.sendEmptyMessageDelayed(MSG_CONNECT_FAIL, 500L); Log.d(TAG, "handleRemoteException bindService fail retry"); } } private void initHandler() { Log.i(TAG, "determineEventHandler is called mHandlerThread:" + mHandlerThread); if (null == mHandlerThread) { Log.i(TAG, "determineEventHandler mWorkHandler"); mHandlerThread = new HandlerThread("ServiceManager"); mHandlerThread.start(); Looper looper = mHandlerThread.getLooper(); if (looper == null) { Log.e(TAG, "determineEventHandler mHandlerThread.getLooper() == null"); looper = Looper.getMainLooper(); } mWorkHandler = new Handler(looper) { @Override public void handleMessage(Message msg) { Log.i(TAG, "determineEventHandler msg: " + msg.what); ISANaviManager.this.handleMessage(msg); } }; } } private void handleReconnect() { Log.d(TAG, "handleReconnect:"); synchronized (this) { mWorkHandler.removeMessages(MSG_CONNECT_RETRY); mWorkHandler.removeMessages(MSG_CONNECT_FAIL); mConnectionRetryCount = 0; mService = null; mContext.unbindService(mServiceConnectionListener); mWorkHandler.sendEmptyMessageDelayed(MSG_CONNECT_RETRY, 500L); } } protected IBinder getClientBinder(String serviceName) { Log.d(TAG, "getClientBinder:" + serviceName + " ,mIsInit:" + mIsInit); if (!mIsInit) { throw new IllegalStateException("getClientBinder must call init in application first"); } try { IISANaviProxy service = getService(); IBinder binder = service.getService(serviceName); if (binder == null) { Log.d(TAG, "getClientBinder could not get binder for service:" + serviceName); return null; } return binder; } catch (Exception e) { e.printStackTrace(); handleRemoteException(); } return null; } protected String getPackageName() { return mContext.getPackageName(); } /** * 判断服务是否可用 * * @return */ protected boolean isAvailable() { boolean ret = false; synchronized (this) { ret = (mService != null && mBinder != null && mBinder.isBinderAlive() && mBinder.pingBinder()); } if (!ret) { startService(); synchronized (this) { ret = (mService != null && mBinder != null && mBinder.isBinderAlive() && mBinder.pingBinder()); } } Log.d(TAG, "isAvailable: ret " + ret); return ret; } public void registerServiceStatusListener(IServiceStatusChangeListener listener) { if (null != listener) { if (!mServiceStatusListeners.contains(listener)) { mServiceStatusListeners.add(listener); } } } public void unregisterServiceStatusListener(IServiceStatusChangeListener listener) { if (null != listener && mServiceStatusListeners.contains(listener)) { mServiceStatusListeners.remove(listener); } } private void notifyServiceStatusChange(boolean isConnect) { Iterator<IServiceStatusChangeListener> iterator = mServiceStatusListeners.iterator(); while (iterator.hasNext()) { IServiceStatusChangeListener l = iterator.next(); l.onServiceStatusChange(isConnect); } } } 解释这段代码
08-22
package com.hh.launcher.module.main; import java.util.HashMap; import androidx.activity.OnBackPressedCallback; import androidx.activity.result.ActivityResult; import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import android.view.View; import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.listener.OnItemLongClickListener; import com.hh.appfw.base.BaseActivity; import com.hh.appfw.utils.EinkUtils; import com.hh.appfw.utils.PkgUtils; import com.hh.appfw.widget.PageTurningHelper; import com.hh.launcher.R; import com.hh.launcher.databinding.ActivityMainBinding; import com.hh.launcher.model.constant.GlobalConst; import com.hh.launcher.model.constant.HHConst; import com.hh.launcher.model.db.PropHelper; import com.hh.launcher.model.db.utils.AppUtils; import com.hh.launcher.model.entity.MainApp; import com.hh.launcher.model.entity.PkgEntity; import com.hh.launcher.module.apps.AppsActivity; import com.hh.launcher.module.apps.adapter.AppsAdapter; import com.hh.launcher.module.wallpaper.LockWallpaperSettingsActivity; import com.hh.launcher.utils.Logger; import com.hh.launcher.utils.PackageUtil; import com.hh.launcher.utils.PkgEntityUtil; import com.hh.launcher.utils.StringUtils; import com.hh.launcher.widgets.AppInfoDialog; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MainActivity extends BaseActivity<ActivityMainBinding, MainVM> implements MainEvent { private final String TAG = "MainActivity"; private MainAdapter mainAdapter; private ActivityResultLauncher<Intent> appsLauncher; private Map<String, PkgEntity> pkgEntityMap; @Override protected int getLayoutResId() { return R.layout.activity_main; } @Override public void init(@Nullable Bundle savedInstanceState) { binding.setViewModel(viewModel); binding.setViewEvent(this); // 在App中创建文件夹(无需root) File dir = new File(Environment.getExternalStorageDirectory(), "Wallpaper"); if (!dir.exists()) { dir.mkdirs(); // 没有就创建,在/sdcard/YourFolder创建 } // AppUtils.removeApp(this, "com.android.vending"); AppUtils.addApp(this, "com.android.vending"); List<MainAppView> list = new ArrayList<>(); list.add(binding.appView01); list.add(binding.appView02); list.add(binding.appView03); list.add(binding.appView04); list.add(binding.appView05); list.add(binding.appView06); list.add(binding.appView07); list.add(binding.appView08); mainAdapter = new MainAdapter(this); mainAdapter.setNewViews(list); appsLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), appsCallback); mainAdapter.setOnPageChangeListener((adapter, pageIndex, pageTotal) -> { logger.e("pageIndex = " + pageIndex + " | pageTotal = " + pageTotal); binding.txtAppPage.setText((pageIndex + 1) + " / " + pageTotal); }); mainAdapter.setOnItemClickListener((adapter, itemView, position) -> { MainApp item = mainAdapter.getItem(position); Log.i(TAG, "click!!!!"); if (item.category == MainApp.CATEGORY_APP) { Intent intent = PkgUtils.getLaunchIntent(MainActivity.this, item.pkgName); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } else { Intent intent = new Intent(MainActivity.this, AppsActivity.class); if (appsLauncher != null) { appsLauncher.launch(intent); } else { startActivity(intent); } } }); for (MainAppView mainAppView : list) { new PageTurningHelper<>(mainAppView, appTurning); } new PageTurningHelper<>(binding.layoutAppRow1, appTurning); new PageTurningHelper<>(binding.layoutAppRow2, appTurning); registerReceiver(); initPreInstallApp(); loadApps(); updatePkgEntityMap(mainAdapter.getListObjects()); // 应用长按 mainAdapter.setOnItemLongClickListener((adapter, itemView, position) -> { MainApp item = mainAdapter.getItem(position); Log.i(TAG, "long click!!!!"); if (item.category == MainApp.CATEGORY_APP) { PkgEntity pkgEntity = pkgEntityMap.get(item.pkgName); if(pkgEntity != null) { AppInfoDialog infoDialog = new AppInfoDialog(this, pkgEntity); infoDialog.show(); } else { Log.w(TAG, "pkgEntity is null"); } } return false; }); // 禁用返回键 getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { logger.e(" OnBackPressed "); } }); } @Override protected void onDestroy() { unregisterReceiver(pkgReceiver); super.onDestroy(); } private final BroadcastReceiver pkgReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (TextUtils.isEmpty(action)) { Logger.e("pkg receiver action is null"); return; } String dataString = intent.getDataString(); if (TextUtils.isEmpty(dataString) || !dataString.startsWith("package")) { Logger.e("dataString return"); return; } String pkg = dataString.substring("package".length() + 1); if (action.equals(Intent.ACTION_PACKAGE_ADDED)) { Logger.e("install app ->" + dataString); AppUtils.addApp(MainActivity.this, pkg); loadApps(); } if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) { Logger.e("remove app ->" + dataString); AppUtils.removeApp(MainActivity.this, pkg); loadApps(); } } }; private void registerReceiver() { IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); pkgFilter.addDataScheme("package"); registerReceiver(pkgReceiver, pkgFilter); } private void doPerInstallAppDB(Context context, String pkg) { if (PkgUtils.isInstall(context, pkg)) { AppUtils.addApp(context, pkg); } } private void initPreInstallApp() { PropHelper propHelper = viewModel.getPropHelper(); if (propHelper.isFirstStart()) { propHelper.setFirstStart(false); String[] initPkgApps = new String[]{ // "com.cpuid.cpu_z", "com.keph.auth", "com.incube.epub.pad", // "com.iwg.music", "com.doosandonga.app.dictionary.primekorkor", // "com.yes24.library.eink", "com.estmob.android.sendanywhere", // "com.android.chrome", "com.hh.guide" // }; for (String initPkgApp : initPkgApps) { doPerInstallAppDB(this, initPkgApp); } } } private void loadApps() { List<MainApp> appList = AppUtils.getAppList(this); MainApp mainApp = getAddApp(); appList.add(mainApp); mainAdapter.setNewObjects(appList); // 更新 pkgEntityMap updatePkgEntityMap(appList); Log.d(TAG,"installing app ..."); } private void updatePkgEntityMap(List<MainApp> appList) { List<String> packageNames = new ArrayList<>(); for (MainApp app : appList) { if (app.pkgName != null && !app.pkgName.isEmpty() && app.category == MainApp.CATEGORY_APP) { packageNames.add(app.pkgName); } } List<PkgEntity> pkgEntities = PkgEntityUtil.buildPkgEntityList(this, packageNames); // 更新 pkgEntityMap pkgEntityMap = pkgEntities.stream() .filter(pkgEntity -> pkgEntity != null && pkgEntity.getPackageName() != null) .collect(Collectors.toMap( PkgEntity::getPackageName, pkgEntity -> pkgEntity, (existing, replacement) -> existing, HashMap::new )); } public MainApp getAddApp() { MainApp app = new MainApp(); app.category = MainApp.CATEGORY_ADD; return app; } private final ActivityResultCallback<ActivityResult> appsCallback = o -> { if (o.getResultCode() == RESULT_OK) { loadApps(); } }; @Override public void onTestClick(View view) { EinkUtils.fullRefresh(this, binding.getRoot()); } @Override public void onTestQuickClick(View view) { startActivity(new Intent(HHConst.ACTION_QUICK_SETTINGS)); } @Override public void onTestSettingsClick(View view) { logger.i("onTestSettingsClick"); Context context = view.getContext(); Intent intent = new Intent(context, LockWallpaperSettingsActivity.class); context.startActivity(intent); // startActivity(new Intent(HHConst.ACTION_SETTINGS_VIEW)); } @Override public void onTestTaskClick(View view) { startActivity(new Intent(HHConst.ACTION_TASK_MANAGER)); } @Override public void onClubClick(View view) { // 清除目标应用任务栈并重新启动 Intent intent = PkgUtils.getLaunchIntent(this, "com.yes24.ebook.einkstore"); if (intent != null) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); } } @Override public void onShelfClick(View view) { // showToast("shelf click"); try { // com.yes24.ebook.einkstore // com.yes24.library.eink Intent intent = PkgUtils.getLaunchIntent(this, "com.yes24.ebook.einkstore"); if (intent != null) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } } catch (Exception e) { e.printStackTrace(); } } @Override public void onNoteClick(View view) { // com.keph.mynote Intent intent = PkgUtils.getLaunchIntent(this, "com.keph.mynote"); if (intent != null) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } } private final PageTurningHelper.OnTurnPageListener appTurning = new PageTurningHelper.OnTurnPageListener() { @Override public void onPrev() { mainAdapter.toPrevPage(); } @Override public void onNext() { mainAdapter.toNextPage(); } }; }如果MainActivity是这样的应该如何添加接收器
12-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值