Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] 那些零碎的知识点 #49

Open
fred-ye opened this issue Jun 11, 2015 · 0 comments
Open

[Android] 那些零碎的知识点 #49

fred-ye opened this issue Jun 11, 2015 · 0 comments

Comments

@fred-ye
Copy link
Owner

fred-ye commented Jun 11, 2015

Android 中那些零碎的知识点

1 IntentService

IntentServiceService的子类,用来处理同步的请求。在IntentService中会开一个工作线程来处理请求。我们可以通过类似于启动Service的方来来启动一个IntentService, IntentService每创建一次,就会新开启一个工作线程来执行请求。执行完一个intent请求对应的工作后,如果没有新的请求到达,则自动停止IntentService, 否则会执行下一个请求。所有需要在后台运行的逻辑我们需要写在onHandleIntent方法中。感觉网上有些博客没说得太清楚,这里自己写个Demo, 加深一下印象

来看这么一段代码:

MyIntentService

public class MyIntentService extends IntentService {
    private final static String TAG = "MyIntentService";
    public MyIntentService() {
        super(TAG);

    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate pid:" + android.os.Process.myPid() + "    thread id:" + Thread.currentThread().getId());

    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.i(TAG, "onHandleIntent pid:" + android.os.Process.myPid() + "    thread id:" + Thread.currentThread().getId());
    }
}

调用者

假设这个代码是当用户点击一个按钮后执行的。

Log.i(TAG, "caller pid:" + android.os.Process.myPid() + "    thread id:" + Thread.currentThread().getId());
startService(new Intent(AActivity.this, MyIntentService.class));
try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
startService(new Intent(AActivity.this, MyIntentService.class));

运行后发现

06-11 09:36:39.113    1680-1680/? I/AActivity﹕ caller pid:1680    thread id:1
06-11 09:36:42.118    1680-1680/? I/MyIntentService﹕ onCreate pid:1680    thread id:1
06-11 09:36:42.119    1680-1703/? I/MyIntentService﹕ onHandleIntent pid:1680    thread id:163
06-11 09:36:42.119    1680-1703/? I/MyIntentService﹕ onHandleIntent pid:1680    thread id:163

在这个例子通过观察线程id,发现虽然启动了两次这个IntentService,但IntentService只创建了一次。

如果我们将调用的代码改成

Log.i(TAG, "caller pid:" + android.os.Process.myPid() + "    thread id:" + Thread.currentThread().getId());
startService(new Intent(AActivity.this, MyIntentService.class));

同样假设这个代码是当用户点击一个按钮时执行。若用户连续点击这个按钮两次,运行结果发现

06-11 09:45:35.454    1784-1784/? I/AActivity﹕ caller pid:1784    thread id:1
06-11 09:45:35.469    1784-1784/? I/MyIntentService﹕ onCreate pid:1784    thread id:1
06-11 09:45:35.469    1784-1807/? I/MyIntentService﹕ onHandleIntent pid:1784    thread id:169
06-11 09:45:35.773    1784-1784/? I/AActivity﹕ caller pid:1784    thread id:1
06-11 09:45:35.777    1784-1784/? I/MyIntentService﹕ onCreate pid:1784    thread id:1
06-11 09:45:35.777    1784-1809/? I/MyIntentService﹕ onHandleIntent pid:1784    thread id:170

在这个例子中,会发现,当IntentService处理完一个请求后,确实会将自己销毁。若此下一个请求来了,会再重新创建一个。所以发现两次的thread id不一样。

IntentService和Service一个重大的差别是在于,IntentService是会开一个工作线程来处理作务,而Service不会,因此Service中不能执行非常耗时的操作,否则会抛异常。下面便是一种验证方式:

@Override
public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
    Log.i(TAG, "onStart");
    //以下代码写在Service的onStart方法中会抛异常,但写在IntentService的onHandleIntent中不会。
    try {
        Thread.sleep(20000); 
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

2 PendingIntent

PendingIntent 是对Intent的一个包装,用来处理未来发生的事。PendingIntent中会保存当前app的Context, 即使当前app已经停止了,仍然可以通过PendingIntent中的Context来执行Intent,通常与AlarmManagerNotificationManager在一起使用。这里有一个示例:

public void testPendingIntent() {
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    long when = System.currentTimeMillis();// 通知发生的时间为系统当前时间
    int icon = android.R.drawable.stat_notify_chat;
    //第一个参数为图标 , 第二个参数为短暂提示标题 , 第三个为通知时间
    Notification notification = new Notification(icon, "TEST Notification", when);
    notification.defaults = Notification.DEFAULT_SOUND;// 发出默认声音
    notification.flags = Notification.FLAG_AUTO_CANCEL;// 点击后自动清除通知
    Intent openintent = new Intent(this, BActivity.class);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, openintent, 0);
    notification.setLatestEventInfo(this, "This is title", "Content", contentIntent);
    manager.notify(0, notification);// 第一个参数为自定义的通知唯一标识
}

3 输入字符转换

之前有这么一个需求,某个EditText中接收的英文字母只能是大写的。当看到这个需求,我们的第一反应是设对这个EditText设置其键盘弹出属性android:inputType="textCapCharacters"。但是既使这样,用户是可以切换到小写模式下。当然或许我们还可以尝试其它的属性,但是想要统一各种机子上输入法的控制是比较难的,确实有些机子的输入法被产商弄得很奇葩,不受你的控制。我们可以用以下这种方式,自动将其转为大写的样式。

定义一个Util类

public class InputLowerToUpperTrans extends ReplacementTransformationMethod {
    @Override
    protected char[] getOriginal() {
        char[] lower = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' };
        return lower;
    }

    @Override
    protected char[] getReplacement() {
        char[] upper = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
        return upper;
    }
}

调用处

etTest.setTransformationMethod(new InputLowerToUpperTrans());

4 LocalBroadcastManager

在Android中,对于大部分app而言,发送广播时,只希望广播被自己app内部的receiver监听到,此时我们可以采用LocalBroadcastManager发送广播,安全性高,效率也高。
具体使用:
1. 写一个BroadcastReceiver, 和通常写法一样

public class MyReceiver extends BroadcastReceiver{
    public final static String TAG = "MyReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "------onReceive------");
    }

}

2. 注册我把它写到onResume里面

@Override
protected void onResume() {
    super.onResume();        
    myReceiver = new MyReceiver();
    IntentFilter filter = new IntentFilter();  
    filter.addAction(ACTION); //ACTION是自己定义的一个成员变量
    LocalBroadcastManager.getInstance(MainActivity.this).registerReceiver(myReceiver, filter);
}

3. 解注册

@Override
protected void onStop() {
    super.onStop();
    LocalBroadcastManager.getInstance(MainActivity.this).unregisterReceiver(myReceiver);
}

4. 发广播

Intent intent = new Intent();
intent.setAction(ACTION);//ACTION是自己定义的一个成员变量
LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(intent);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant