A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小鲁哥哥 于 2017-4-12 14:32 编辑

Android课程同步笔记day11:Android应用之安全卫士

Widget_窗口小部件
通过查询官网Api教程,发现实现一个应用的widget小窗口遵循以下几个步骤即可快速实现。
第一步:
xxxxx.receiver包下创建一个类ProcessWidgetProvider:
[Java] 纯文本查看 复制代码
public class ProcessWidgetProvider extends AppWidgetProvider {
}
清单文件注册:
[XML] 纯文本查看 复制代码
<receiver android:name=".receiver.ProcessWidgetProvider" >
     <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
     </intent-filter>

     <meta-data
          android:name="android.appwidget.provider"
          android:resource="@xml/process_widget_provider" />
 </receiver>
这里面需要在xml文件夹下创建一个process_widget_provider的xml文件。
第二步:
Res/xml文件夹下创建一个process_widget_provider的xml文件:
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/process_widget"
    android:minHeight="72.0dip"
    android:minWidth="294.0dip"
android:updatePeriodMillis="0" />
这里需要指定一个布局文件process_widget.xml,也就是widget小窗口的UI布局。
第三步:
Res/layout 文件夹下创建process_widget.xml,这里直接拷贝的金山卫士布局,只需要将里面的一些图片资源替换为我们自己应用的图片即可。直接拷贝布局即可,然后里面报红线的资源文件找不到,直接到金山卫士资源文件中或者我给的安全卫士代码资源下复制过来
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/widget_bg_portrait"
    android:gravity="center_vertical" >

    <LinearLayout
        android:layout_width="0.0dip"
        android:layout_height="fill_parent"
        android:layout_marginLeft="5.0dip"
        android:layout_weight="1.0"
        android:background="@drawable/widget_bg_portrait_child"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:paddingBottom="3.0dip"
        android:paddingTop="3.0dip" >

        <TextView
            android:id="@+id/process_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10.0dip"
            android:textAppearance="@style/widget_text" />

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="1.0dip"
            android:layout_marginTop="1.0dip"
            android:background="@drawable/widget_bg_portrait_child_divider" />

        <TextView
            android:id="@+id/process_memory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10.0dip"
            android:textAppearance="@style/widget_text" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_vertical" >

            <ImageView
                android:layout_width="20.0dip"
                android:layout_height="20.0dip"
                android:src="@drawable/ic_launcher" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/app_name"
                android:textColor="@color/textColorPrimary" />
        </LinearLayout>

        <Button
            android:id="@+id/btn_clear"
            android:layout_width="90.0dip"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginTop="5.0dip"
            android:background="@drawable/function_greenbutton_selector"
            android:text="一键清理"
            android:textColor="@color/function_greenbutton_textcolor_selector" />
    </LinearLayout>
</LinearLayout>
通过以上三步即可显示一个当前应用的widget窗口小部件。
不过在我们手机卫士应用中的widget需要时时去刷新当前系统中正在运行的进程以及占用的内存信息,所以还需要进行widget的更新操作。
在ProcessWidgetProvider中可以去实现父类的onUpdate方法去更新widget;不过该方法系统提供的是每15分钟才更新一次,这显然不符合我们的需求;我们需要每隔2S就更新一次;那么为了达到这种需求可以开启一个服务来实现
[Java] 纯文本查看 复制代码
public class ProcessWidgetProvider extends AppWidgetProvider {

        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                        int[] appWidgetIds) {
                 // 15分钟更新一次
                context.startService(new Intent(context, ProcessService.class));
        }
}
ProcessService服务在被开启的时候我们可以开启一个子线程(为了不阻塞主线程),在子线程中做一个死循环去更新widget,google给我们提供更新widget的方法就是:AppWidgetManager.getInstance(ProcessService.this)
                      .updateAppWidget(provider, views);
所以死循环中执行一次update再睡眠两秒即可达到我们的每隔两秒更新一个widget的需求:
[Java] 纯文本查看 复制代码
public class ProcessService extends Service {

        private ScreenReceiver mReceiver;
        private boolean isRunning;

        @Override
        public IBinder onBind(Intent intent) {
                // TODO Auto-generated method stub
                return null;
        }

        @Override
        public void onCreate() {
                super.onCreate();

                // 在锁屏时不要去更新UI,解锁屏幕时需要去更新
                mReceiver = new ScreenReceiver();
                IntentFilter filter = new IntentFilter();
                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
                filter.addAction(Intent.ACTION_SCREEN_OFF);// 锁屏
                filter.addAction(Intent.ACTION_SCREEN_ON);// 屏幕解锁

                registerReceiver(mReceiver, filter);

                start();
        }

        private void start() {
                isRunning = true;
                new Thread(new Runnable() {
                        @Override
                        public void run() {

                                while (isRunning) {
                                        // 15分钟
                                        ComponentName provider = new ComponentName(
                                                        ProcessService.this, ProcessWidgetProvider.class);
                                        RemoteViews views = new RemoteViews(ProcessService.this
                                                        .getPackageName(), R.layout.process_widget);
                                        // 1.显示进程数
                                        int runningProcessCount = ProcessProvider
                                                        .getRunningProcessCount(ProcessService.this);
                                        views.setTextViewText(R.id.process_count, "正在运行的进程数:"
                                                        + runningProcessCount);

                                        // 2.显示可用的内存
                                        long freeMemory = ProcessProvider.getTotalMemory()
                                                        - ProcessProvider
                                                                        .getUsedMemory(ProcessService.this);
                                        views.setTextViewText(
                                                        R.id.process_memory,
                                                        "可用内存:"
                                                                        + Formatter.formatFileSize(
                                                                                        ProcessService.this, freeMemory));

                                        // 3.点击事件
                                        // 延期意图:打开activity,发送广播,开启服务
                                        Intent intent = new Intent(ProcessService.this,
                                                        KillProcessService.class);
                                        PendingIntent pendingIntent = PendingIntent.getService(
                                                        ProcessService.this, 100, intent,
                                                        PendingIntent.FLAG_UPDATE_CURRENT);
                                        views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);

                                        //每隔2S更新widget
                                        AppWidgetManager.getInstance(ProcessService.this)
                                                        .updateAppWidget(provider, views);

                                        try {
                                                Thread.sleep(2000);
                                        } catch (InterruptedException e) {
                                                e.printStackTrace();
                                        }
                                }
                        }
                }).start();
        }

        @Override
        public void onDestroy() {
                super.onDestroy();
                isRunning = false;
                unregisterReceiver(mReceiver);
        }

        private class ScreenReceiver extends BroadcastReceiver {
                @Override
                public void onReceive(Context context, Intent intent) {
                        // 判断是解锁还是锁屏
                        String action = intent.getAction();
                        if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                                // 锁屏
                                // 停止更新
                                isRunning = false;
                        } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                                // 解锁
                                // 开启更新
                                start();
                        }
                }
        }
}
注意上诉代码中监听了锁屏的处理,目的是为了节省内存资源开销,如果手机已处于锁屏状态那么我们的while循环就不需要再执行了。
上诉代码中我们找到了控件中的一键清理按钮,给该按钮做了一个点击事件的监听,当用户点击了一键清理意味着需要手动去清理当前的进程,可以通过注册一个广播事件来接收该操作,但是这里给大家引入一个IntentService服务来操作:IntentService是一个基于Service的一个类,用来处理异步的请求。你可以通过startService(Intent)来提交请求,该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。
我们使用了IntentService最起码有两个好处,一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了
[Java] 纯文本查看 复制代码
public class KillProcessService extends IntentService {
        private Handler handler = new Handler();
        public KillProcessService() {
                super("KillProcessService");
        }

        @Override
        protected void onHandleIntent(Intent intent) {
                // 1. 是在子线程中执行的(可以执行耗时的操作)
                // 2. 多次同时调用服务,onHandleIntent会排队执行,等所有的方法调用完成后,服务就销毁
                // 3. 单次开启服务,onHandleIntent执行完成后,服务销毁

                int beforeCount = ProcessProvider.getRunningProcessCount(this);
                long beforeMemory = ProcessProvider.getUsedMemory(this);

                // 杀死进程
                List<ProcessBean> processes = ProcessProvider.getProcesses(this);
                for (ProcessBean bean : processes) {
                        String packageName = bean.pkg.packageName;
                        if (packageName.equals(getPackageName())) {
                                continue;
                        }
                        ProcessProvider.killProcess(this, packageName);
                }

                int afterCount = ProcessProvider.getRunningProcessCount(this);
                long afterMemory = ProcessProvider.getUsedMemory(this);

                final int count = beforeCount - afterCount;// 杀死的进程数

                if (count > 0) {
                        final long memory = beforeMemory - afterMemory;

                        handler.post(new Runnable() {
                                @Override
                                public void run() {
                                        Toast.makeText(
                                                        KillProcessService.this,
                                                        "杀死了"
                                                                        + count
                                                                        + "进程,节省内存"
                                                                        + Formatter.formatFileSize(
                                                                                        KillProcessService.this, memory),
                                                        Toast.LENGTH_SHORT).show();
                                }
                        });
                } else {
                        handler.post(new Runnable() {

                                @Override
                                public void run() {
                                        Toast.makeText(KillProcessService.this, "没有可以优化的",
                                                        Toast.LENGTH_SHORT).show();
                                }
                        });
                }
        }
}
最后实现的效果图如下:

AsyncTask
在Android中实现异步任务机制有两种方式,Handler和AsyncTask。
Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。
为了简化操作,Android1.5提供了工具类android.os.AsyncTask,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。
先来看看AsyncTask的定义:
public abstract class AsyncTask<Params,Progress, Result>
三种泛型类型分别代表“启动任务执行的输入参数”、“后台任务执行的进度”、“后台计算结果的类型”。在特定场合下,并不是所有类型都被使用,如果没有被使用,可以用Java.lang.Void类型代替。
一个异步任务的执行一般包括以下几个步骤:
1.execute(Params... params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
2.onPreExecute(),在execute(Params... params)被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。
3.doInBackground(Params... params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress(Progress... values)来更新进度信息。
4.onProgressUpdate(Progress... values),在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。
5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
在使用的时候,有几点需要格外注意:
1.异步任务的实例必须在UI线程中创建。
2.execute(Params... params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params...params),onProgressUpdate(Progress...values),onPostExecute(Resultresult)这几个方法。
4.不能在doInBackground(Params... params)中更改UI组件的信息。
5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。
如果有对源码感兴趣,想深入研究的同学可以参考下面这篇文章:

流量统计流量统计的主要效果就是获取当前的所有已安装应用程序,通过列表展示流量的消耗,效果图如下

不过注意的是如果是在模拟器上运行,所有的应用程序是获取不到流量数据的;只有在真机上测试才能看到。
首先第一步,创建TrafficActivity,然后实现里面布局xml:
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        style="@style/titleBarStyle"
        android:text="流量统计" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <ListView
            android:id="@+id/traffic_listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        </ListView>

        <include layout="@layout/include_loading" />
    </RelativeLayout>

</LinearLayout>

第二步,实现每一个条目的item布局xml:
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp" >

    <ImageView
        android:id="@+id/item_traffic_iv_icon"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_centerVertical="true"
        android:src="@drawable/ic_default" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="8dp"
        android:layout_toRightOf="@id/item_traffic_iv_icon"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/item_traffic_tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="名称" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/item_traffic_tv_receive"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="接收" />

            <TextView
                android:id="@+id/item_traffic_tv_send"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:text="发送" />
        </RelativeLayout>
    </LinearLayout>

</RelativeLayout>

第三步,准备条目javaBean:TrafficBean
[Java] 纯文本查看 复制代码
public class TrafficBean {
        public Drawable icon;
        public String name;
        public long receive;
        public long send;
}

第四步,初始化控件,将listview ui展示出来:
[Java] 纯文本查看 复制代码
public class TrafficActivity extends Activity {
        private ListView mListView;
        private View mLoadingView;

        private List<TrafficBean> mDatas;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_traffic);

                initView();
                initData();
        }

        private void initView() {
                mListView = (ListView) findViewById(R.id.traffic_listview);
                mLoadingView = findViewById(R.id.include_ll_loading);
        }

        private void initData() {
                // 假数据

                new AsyncTask<Void, Void, Void>() {
                        protected void onPreExecute() {
                                // 进度显示
                                mLoadingView.setVisibility(View.VISIBLE);
                                // mDatas = new ArrayList<TrafficBean>();
                        };

                        @Override
                        protected Void doInBackground(Void... params) {

                                mDatas = TrafficProvider.getTraffics(TrafficActivity.this);
                                System.out.println("data:"+mDatas.toString());
                                return null;
                        }

                        protected void onPostExecute(Void result) {
                                // 进度隐藏
                                mLoadingView.setVisibility(View.GONE);

                                // 设置adapter
                                mListView.setAdapter(new TrafficAdapter());
                        };
                }.execute();

        }

        private class TrafficAdapter extends BaseAdapter {

                @Override
                public int getCount() {
                        if (mDatas != null) {
                                return mDatas.size();
                        }
                        return 0;
                }

                @Override
                public Object getItem(int position) {
                        if (mDatas != null) {
                                return mDatas.get(position);
                        }
                        return null;
                }

                @Override
                public long getItemId(int position) {
                        return position;
                }

                @Override
                public View getView(int position, View convertView, ViewGroup parent) {
                        ViewHolder holder = null;
                        if (convertView == null) {
                                convertView = View.inflate(TrafficActivity.this,
                                                R.layout.item_traffic, null);
                                holder = new ViewHolder();
                                convertView.setTag(holder);
                                holder.ivIcon = (ImageView) convertView
                                                .findViewById(R.id.item_traffic_iv_icon);
                                holder.tvName = (TextView) convertView
                                                .findViewById(R.id.item_traffic_tv_name);
                                holder.tvReceive = (TextView) convertView
                                                .findViewById(R.id.item_traffic_tv_receive);
                                holder.tvSend = (TextView) convertView
                                                .findViewById(R.id.item_traffic_tv_send);
                        } else {
                                holder = (ViewHolder) convertView.getTag();
                        }

                        // 设置数据
                        TrafficBean bean = mDatas.get(position);

                        if (bean.icon == null) {
                                holder.ivIcon.setImageResource(R.drawable.ic_default);
                        } else {
                                holder.ivIcon.setImageDrawable(bean.icon);
                        }
                        holder.tvName.setText(bean.name);
                        holder.tvReceive.setText("接收:"
                                        + Formatter.formatFileSize(TrafficActivity.this,
                                                        bean.receive));
                        holder.tvSend
                                        .setText("发送:"
                                                        + Formatter.formatFileSize(TrafficActivity.this,
                                                                        bean.send));

                        return convertView;
                }
        }

        private static class ViewHolder {
                ImageView ivIcon;
                TextView tvName;
                TextView tvSend;
                TextView tvReceive;
        }
}

其实listview展示所需要的数据是通过业务逻辑类TrafficProvider来获取:
[Java] 纯文本查看 复制代码
public class TrafficProvider {
        /**
         * 获得流量信息
         * 
         * @param context
         * @return
         */
        public static List<TrafficBean> getTraffics(Context context) {
                List<TrafficBean> list = new ArrayList<TrafficBean>();

                PackageManager pm = context.getPackageManager();
                // 获得所有应用程序的发送和接收的情况
                List<PackageInfo> packages = pm.getInstalledPackages(0);

                for (PackageInfo info : packages) {

                        Drawable icon = PackageUtils.getAppIcon(context, info);
                        String name = PackageUtils.getAppName(context, info);

                        int uid = info.applicationInfo.uid;
                        long receive = getReceive(uid);
                        long send = getSend(uid);

//                        if (receive == 0 && send == 0) {
//                                continue;
//                        }

                        TrafficBean bean = new TrafficBean();
                        bean.icon = icon;
                        bean.name = name;
                        bean.receive = receive;
                        bean.send = send;

                        list.add(bean);
                }

                return list;
        }

        // proc/uid_stat/xxxx/tcp_rcv -->接收的数据
        private static long getReceive(int uid) {
                String path = "/proc/uid_stat/" + uid + "/tcp_rcv";

                BufferedReader reader = null;

                try {
                        reader = new BufferedReader(new FileReader(new File(path)));
                        String readLine = reader.readLine();
                        return Long.valueOf(readLine);
                } catch (Exception e) {
                        return 0;
                } finally {
                        StreamUtils.closeIO(reader);
                }
        }

        // proc/uid_stat/xxxx/tcp_snd --> 发送的数据
        private static long getSend(int uid) {
                String path = "/proc/uid_stat/" + uid + "/tcp_snd";

                BufferedReader reader = null;

                try {
                        reader = new BufferedReader(new FileReader(new File(path)));
                        String readLine = reader.readLine();
                        return Long.valueOf(readLine);
                } catch (Exception e) {
                        return 0;
                } finally {
                        StreamUtils.closeIO(reader);
                }
        }
}

常用工具
在常用工具中添加两个比较实用的小工具,一个是短信备份,一个是短信还原;这两个工具都是在基础已经就实现过的,没什么难度,主要是如何优化的问题;效果图如下:

实现一个短信备份和还原没什么难度,但问题就是如何做出一个可以提供给别人使用,将UI和代码逻辑完全隔离,解耦的工具类;这里需要借助到一个很重要的思想:接口回调。通过接口回调来实现代码的解耦,隔离。
下面来看下我们的业务逻辑类的实现
[Java] 纯文本查看 复制代码
public class SmsProvider {
        
        public static void smsBackup(final Context context,
                        final OnSmsListener listener) {
                new AsyncTask<Void, Integer, Boolean>() {
                        @Override
                        protected void onPreExecute() {
                                // 显示进度
                                // dialog.show();// 准备阶段
                                if (listener != null) {
                                        listener.onPre();
                                }
                        }
                        @Override
                        protected Boolean doInBackground(Void... params) {
                                boolean flag = true;
                                try {
                                        // 1.读取系统短信
                                        ContentResolver cr = context.getContentResolver();
                                        Uri uri = Uri.parse("content://sms");
                                        String[] projection = new String[] { "address", "date",
                                                        "read", "type", "body" };
                                        String selection = null;
                                        String[] selectionArgs = null;
                                        String sortOrder = null;
                                        Cursor cursor = cr.query(uri, projection, selection,
                                                        selectionArgs, sortOrder);

                                        List<SmsBean> list = new ArrayList<SmsBean>();
                                        if (cursor != null) {
                                                int count = cursor.getCount();
                                                int progress = 0;
                                                // 推出大小
                                                publishProgress(count, progress);
                                                while (cursor.moveToNext()) {

                                                        String address = cursor.getString(0);
                                                        long date = cursor.getLong(1);
                                                        int read = cursor.getInt(2);
                                                        int type = cursor.getInt(3);
                                                        String body = cursor.getString(4);

                                                        SmsBean bean = new SmsBean();
                                                        bean.address = address;
                                                        bean.date = date;
                                                        bean.read = read;
                                                        bean.type = type;
                                                        bean.body = body;

                                                        list.add(bean);

                                                        // 推出进度
                                                        publishProgress(count, ++progress);

                                                        Thread.sleep(50);
                                                }
                                                cursor.close();
                                        }

                                        // 存储-->SD中: json
                                        // 将对象转换为json字符串,将字符串存到文件中
                                        Gson gson = new Gson();
                                        String json = gson.toJson(list);

                                        // 存储为文件
                                        File file = new File(
                                                        Environment.getExternalStorageDirectory(),
                                                        "sms.json");
                                        BufferedWriter writer = null;
                                        try {
                                                writer = new BufferedWriter(new FileWriter(file));
                                                writer.write(json);
                                        } finally {
                                                StreamUtils.closeIO(writer);
                                        }

                                } catch (Exception e) {
                                        flag = false;
                                }
                                return flag;
                        }

                        @Override
                        protected void onProgressUpdate(Integer... values) {
                                Integer max = values[0];
                                Integer progress = values[1];
                                // dialog.setMax(max);// 进度阶段:
                                // dialog.setProgress(progress);

                                if (listener != null) {
                                        listener.onProgress(max, progress);
                                }
                        }

                        @Override
                        protected void onPostExecute(Boolean result) {
                                // dialog.dismiss();// 结果阶段:
                                if (listener != null) {
                                        listener.onFinish(result);
                                }
                        }
                }.execute();
        }

        public static void smsRestore(final Context context,
                        final OnSmsListener listener) {
                // 读取短信备份的文件---》对象---》插入数据 --->UI显示

                new AsyncTask<Void, Integer, Boolean>() {

                        @Override
                        protected void onPreExecute() {
                                super.onPreExecute();

                                if (listener != null) {
                                        listener.onPre();
                                }
                        }

                        @Override
                        protected Boolean doInBackground(Void... params) {
                                List<SmsBean> list = new ArrayList<SmsBean>();

                                // 读取短信文件
                                File file = new File(Environment.getExternalStorageDirectory(),
                                                "sms.json");

                                BufferedReader reader = null;
                                try {
                                        reader = new BufferedReader(new FileReader(file));
                                        String json = reader.readLine();

                                        Gson gson = new Gson();
                                        list = gson.fromJson(json, new TypeToken<List<SmsBean>>() {
                                        }.getType());

                                        // 获得总大小
                                        int count = list.size();
                                        int progress = 0;
                                        publishProgress(count, progress);

                                        ContentResolver cr = context.getContentResolver();
                                        Uri url = Uri.parse("content://sms");
                                        for (int i = 0; i < list.size(); i++) {
                                                SmsBean bean = list.get(i);
                                                // 逐条插入
                                                ContentValues values = new ContentValues();
                                                values.put("address", bean.address);
                                                values.put("date", bean.date);
                                                values.put("read", bean.read);
                                                values.put("type", bean.type);
                                                values.put("body", bean.body);
                                                cr.insert(url, values);

                                                publishProgress(count, ++progress);

                                                Thread.sleep(50);
                                        }

                                } catch (Exception e) {
                                        return false;
                                } finally {
                                        StreamUtils.closeIO(reader);
                                }

                                return true;
                        }

                        @Override
                        protected void onProgressUpdate(Integer... values) {

                                int max = values[0];
                                int progress = values[1];
                                if (listener != null) {
                                        listener.onProgress(max, progress);
                                }
                        }

                        @Override
                        protected void onPostExecute(Boolean result) {

                                if (listener != null) {
                                        listener.onFinish(result);
                                }
                        }
                }.execute();

        }

        public interface OnSmsListener{
                void onPre();// 准备阶段

                void onProgress(int max, int progress);// 进度阶段

                void onFinish(boolean sucess);// 结束阶段
        }
}

代码的关键就在于,我们在实现备份、还原的过程中,备份前,备份中,备份后,都需要与UI打交道,都需要进行UI的展示和操作;像这类型的业务逻辑就需要用到接口回调。将所有业务逻辑中需要与UI打交道的操作都放在一个接口里面,定义出对应的方法;这些方法不需要写业务逻辑的人来实现,而提供给具体需要调用我们方法的人去实现。
调用该业务逻辑实现短信备份和还原的操作就变得相对来说很灵活和简便了:
[Java] 纯文本查看 复制代码
/**
         * 短信备份
         */
        private void clickSmsBackup() {
                final ProgressDialog dialog = new ProgressDialog(this);
                dialog.setCancelable(false);
                dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

                // final TextView tv = (TextView) findViewById(R.id.ct_siv_tv_progress);
                // 所有的接口只和UI相关
                SmsProvider.smsBackup(this, new OnSmsListener() {
                        @Override
                        public void onPre() {
                                dialog.show();
                                // tv.setVisibility(View.VISIBLE);
                        }
                        @Override
                        public void onProgress(int max, int progress) {
                                dialog.setMax(max);
                                dialog.setProgress(progress);
                                // tv.setText(progress + "/" + max);
                        }
                        @Override
                        public void onFinish(boolean sucess) {
                                // tv.setVisibility(View.GONE);
                                dialog.dismiss();
                                if (sucess) {
                                        Toast.makeText(CommonToolsActivity.this, "备份成功",
                                                        Toast.LENGTH_SHORT).show();
                                } else {
                                        Toast.makeText(CommonToolsActivity.this, "备份失败",
                                                        Toast.LENGTH_SHORT).show();
                                }
                        }
                });
        }
        /**
         * 短信还原
         */
        private void clickSmsRestore() {
                // 读取短信备份的文件---》对象---》插入数据 --->UI显示

                final ProgressDialog dialog = new ProgressDialog(this);
                dialog.setCancelable(false);
                dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                SmsProvider.smsRestore(this, new OnSmsListener() {

                        @Override
                        public void onPre() {
                                dialog.show();
                        }

                        @Override
                        public void onProgress(int max, int progress) {
                                dialog.setMax(max);
                                dialog.setProgress(progress);
                        }

                        @Override
                        public void onFinish(boolean sucess) {
                                dialog.dismiss();
                                if (sucess) {
                                        Toast.makeText(CommonToolsActivity.this, "还原成功",
                                                        Toast.LENGTH_SHORT).show();
                                } else {
                                        Toast.makeText(CommonToolsActivity.this, "还原失败",
                                                        Toast.LENGTH_SHORT).show();
                                }
                        }
                });
        }




3 个回复

倒序浏览
回复 使用道具 举报
回复 使用道具 举报
多谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马