生产APK:
1、点击“Build”——“build(Rebuild) project”
2、打开项目所在目录下的“build”——“outputs”——“apk”——“debug”——“app-debug.apk”
3、由于没有创建规范的key,所以不能生成正式的APK,暂时不忙研究
interface:
目标类继承interface以确定是哪个context在调用
调用的activity需要定义为implements my_interface调用之前要new一下class(在class里面重载该类),就不用设置为static
比如:B类调用A类的接口C
A类 implements C//这个地方把A和C合并了,可以直接传递给B的接收函数
定义 B = new B(C接口)
操作函数()
B类
定义B(C接口)//接收方法
C.接口函数()//调用接口操作A类
C接口
接口函数()
总结起来就是把接口和活动合并,方便传递接口
通过接收方法,把接口传递到要使用接口的类里面,调用接口就调用了操作函数
MVP设计模式:
Model层(模型) + View层(视图) + presenter层(业务逻辑层)
Model模型:类似实体类,json_bean这种类型的实体属性类(或其它能提供数据的类),通过接口给属性赋值或获取属性信息。
View视图:界面的展示,控件的展示和操作。
presenter业务逻辑:实现模型和视图的解耦,通过调用接口分别对模型和视图进行操作,并且模型和视图之间只能通过逻辑层进行交互,VIEW不能直接访问Model
说简单点就是
V通过调用P的接口操作P,来调用P里面操作M的接口来调用或操作M。
MVP模式的优点:
模型与视图完全分离,我们可以修改视图而不影响模型
所有的交互都发生在一个地方——Presenter内部,可以更高效地使用模型
可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁
如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)
MVP模式的缺点:
由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。还有一点需要明白,如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。比如说,原本用来呈现Html的Presenter现在也需要用于呈现Pdf了,那么视图很有可能也需要变更。
总结:
V层和M层不能直接通信,需要通过P层逻辑判断后才能传递信息,传递的方式只能是接口。
比如:
V类 implements V接口
P p= new P(V接口)//定义P接口,需要数据的时候调用接口就行
V_fun(data){ //V接口对应的各种方法
View.settext(data);
}
onclick{ //触发P类中的方法
p.fun()
}
M类(user.class) implements M接口
public M()//重载类,方便P类New一个M接口
M_fun()
P类 implements P接口
M接口 m;
P接口 p;
public P(V接口){//重载类,方便V类New一个P接口,并将V接口传递给M类
p = V接口; //传递V接口到P类
m = new user(); //通过M类实例化M接口(注意不是M类,因为定义的m是M接口类型)
}
public fun(){ //P中的逻辑操作方法,用于V类调用
data = m.v_fun();//通过M接口获取数据
V接口.v_fun(data);//通过V接口传递数据并操作View
}
V接口
v_fun()
M接口
M_fun()
P接口
P_m_fun()
P_v_fun()
fun()
使用:
fragment:
用getFragmentManager.beginTransaction().replace(fragment1.getId(), f1).commit()显示
用fragmentTransaction.hide(f1);隐藏
其中fragment1.getId()是XML中的ID号
f1是自定义的fragment
GSON:
创建JSON格式类 jsonbean
生产json数据类:
Gson gson = new Gson();
jsonbean my_jsonbean = gson.fromjson(jsonstring,jsonbean)
生产json字符串:
Gson gson = new Gson();
String my_jsonstring = gson.tojson(my_jsonbean)
简单GSON 不用建立对应的bean_class
调用系统自带的JSONObject,通过对LIST<hashmap>的访问类型就可以了
JSONObject jsonObject = new JSONObject(result);
String access_token = jsonObject.getString("access_token");
EventBus:
信号接受页需要注册:EventBus.getDefault().register(this);
信号接受页需要定义接受函数:
必须在函数前标记:@Subscribe,函数名必须为onEvent
@Subscribe
public void onEvent(String str) {
myText.setText(str);
};
其中的参数可以为任意event,比如一个类
OkHttp:
只能在子线程使用response获取数据,在主线程使用会报错误NetWorkOnMainThreadException
OkHttpRequest okHttpRequest = new OkHttpRequest();
get:发送后获取返回值,一般目的是从服务器获取信息
accessToken = okHttpRequest.get(accessTokenUrl);
post:发送后获取返回值,一般目的是把信息发送到服务器
data_json = okHttpRequest.post(accessTokenUrl,search_json);
post和get差不多,只是post可以携带需要传输的数据(也可以是文件,文件需要封装)
企业微信的查询就需要携带查询的Json数据(含起始时间,人员名单等)
文件上传:
文件下载:
SQLServer:
添加jtds Jar包到libs后需要点击右键,选择“add as library”
SQLITE:
查询是否存在某数据表:
db = DBHelper.getWritableDatabase();
cursor = db.rawQuery("select name from sqlite_master where type='table' ", null);
遍历查询该表是否存在于查询结果
while (cursor.moveToNext()) {
//遍历出表名
String name = cursor.getString(0);
if (name.equals(table_name)) {
checked = true;
}
}
其中db.rawQuery可执行所有的查询语句(删减查改)
ButterKnife:
软件版本很重要,Android studio 4.1版本需要打开C:\Users\chenyong\AppData\Local\Google\AndroidStudio4.1\plugins目录,把Jar包拷贝到studio的安装目录下的plugins文件夹
同时需要添加lombok依赖,因为自动生成的json.class是通过lombok简化了的
RxJava:
Observable:被观察者
Observer:观察者
subscribe:订阅 observable.subscribe(observer)
观察者四个活动:
public void onSubscribe(Disposable d)具体不清楚,可能是初始化的活动
public void onNext(String s)通过(Observable:被观察者)调用,执行新的操作,实现线程之间的转换
public void onError(Throwable e)(Observable:被观察者)调用过程中出现错误,触发该活动
public void onComplete()(Observable:被观察者)调用过程结束后触发该活动
其中onError和onComplete必须有且只有一个,且要放在序列的最后
综上,感觉最重要的还是onNext活动,实现线程之间的活动传递,其它的都是为它做辅助工作
subscribeOn(Schedulers.newThread())定义(Observable:被观察者)中的subscribe(ObservableEmitter<String> emitter)在哪个线程中执行
observeOn(AndroidSchedulers.mainThread())定义(Observer:观察者)中的活动在哪个线程中执行
subscribe(new Observer<String>()定时(Observer:观察者)的具体活动
RxJava中定义的四种线程:
Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler,不要把计算放进该线程,否则等待的时间会创建不必要的线程。
Schedulers.computation(): 计算时所使用的 Scheduler,不要把I/O放进该线程,否则等待信息反馈的时间会浪费CPU。
AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "FourActivity2 click button", Toast.LENGTH_SHORT).show();
}
});
Retrofit:
//GET 接口
@GET(Constant.UrlOrigin.get_post_info)
Observable<PostInfo> getPostInfoRx(@Query("corpid") String corpid, @Query("corpsecret") String corpsecret);
//先封装一个object类
List<String> lv = new ArrayList<String>();
lv.add("ChenYong");
post_json pj = new post_json(3,starttime, endtime,lv);
//初始化retrofit
// 把数据通过message和handler传递到主线程
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.SERVER_DATA_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava
.client(RetrofitUtils.getOkHttpClient()) // 打印请求参数
.build();
RetrofitService service = retrofit.create(RetrofitService.class);
Observable<wxkq> observable = service.getPostInfoRx2(Access_token,pj);
//Post 接口,使用@Body上传一个实体类(json.class)
public abstract interface RetrofitService
@POST(Constant.UrlOrigin2.get_post_info)
Observable<wxkq> getPostInfoRx2(@Query("access_token") String access_token, @Body post_json pj);
gilde:
public void change_pic(Context context,String Url){
Glide.with(context).load(Url).
thumbnail(Glide.with(context).load(R.drawable.ic_launcher)).//加载图片等待过程显示的东西
diskCacheStrategy(DiskCacheStrategy.SOURCE).//加载图片失败显示的东西
fitCenter().
into(new SimpleTarget<GlideDrawable>() {
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
if (resource.isAnimated()) {
resource.setLoopCount(GifDrawable.LOOP_FOREVER);//设置的重复次数,-1为一直循环,0为不循环,正整数就是循环次数
resource.start();//启动动画,停止用stop
}
}
});
Dagger:
rebuild projects 过后没有生成dagger开头的文件(在build——generated——source里面没有东西),可以在ap-generated-sources里面找。
@Provides 标记为dagger实例
@Component 依赖到某个实例集合
@Inject 引用实例
思路:
新建一个接口MainComponent,设置Component,把Provides(module里面)绑定到MainActivity。
rebuild一下项目
在MainActivity里面添加依赖DaggerMainComponent.create().inject(this);
把MainActivity通过set函数传递到prensenter,在presenter里面通过MainActivity来操作View
bulid显示乱码:
打开help——edit custom vm options——添加代码“-Dfile.encoding=UTF-8”
选择file——invalidata caches/restart
ViewHolder逻辑
1、定义一个静态类,并在类里面申明变量
static class ViewHolder{
TextView textview1;
ImageView imageview1;
}
2、在作用域内声明一个实例化的ViewHolder
ViewHolder my_ViewHolder = new ViewHolder();
3、在作用域内赋值或调用ViewHolder里面的参数
my_ViewHolder.textview1 = (TextView)findViewById(R.id.text1)
my_ViewHolder.textview1.setText("123");
// 通过Context获取Activity
public static Activity getActivityByContext(Context context){
while(context instanceof ContextWrapper){
if(context instanceof Activity){
return (Activity) context;
}
context = ((ContextWrapper) context).getBaseContext();
}
return null;
}
// 通过ID获取View
@SuppressWarnings("unchecked")
public <T extends View> T getView(int id) {
T result = (T) getActivityByContext(context).findViewById(id);
if (result == null) {
throw new IllegalArgumentException("view 0x" + Integer.toHexString(id)
+ " doesn't exist");
}
return result;
}
//拨打电话核心代码
//首先要取得android.permission.CALL_PHONE权限
public void call_phone(String phone_number){
Intent my_call_intent = new Intent("android.intent.action.CALL",Uri.parse("tel:"+phone_number));
startActivity(my_call_intent);
}
//发送短信核心代码
//首先要取得android.permission.CALL_PHONE和android.permission.SEND_MSS权限
public void send_msm(String phone_number,String send_data){
try{
Intent my_send_intent = new Intent(Intent.ACTION_VIEW);
my_send_intent .putExtra("address",phone_number);
my_send_intent .setData(Uri.parse("smsto:"+tel));
my_send_intent .putExtra("sms_body",send_data);
my_send_intent .setType("vnd.android-dir/mms-sms");
startActivity(my_send_intent);
}
catch(ex e){}
}
或者 SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phone_number,null,send_data,null,null);
// Activity之间传递消息(需要finish)
//思路:建立公有静态类,不需要实例化
public class m_change_flag {
static boolean change_flag = false;
public static void save_flag(boolean change_flag1){
change_flag =change_flag1;
}
public static boolean get_flag(){
return change_flag;
}
}
//在Activity加载时调用m_change_flag.get_flag加载数据
//在Activity结束时调用m_change_flag.save_flag保存数据
隐藏的activity
第一步,设置manifest里面的activity属性
android:theme="@android:style/Theme.Translucent.NoTitleBar"//隐藏界面
android:launchMode="singleInstance"//独占模式打开(始终只打开1个界面,如果已打开则不执行打开操作)
android:windowSoftInputMode="adjustResize"//界面缩放(有键盘或其它界面,该界面上的控件会自动缩放或调整位置)
第二步:在activity中执行
moveTaskToBack(true);//使界面回到HOME界面(软件icon所在的桌面界面)
或第二步:在activity中执行
intent=new Intent(Intent.ACTION_MAIN);//指定跳到系统桌面,*ACTION_MAIN:应用程序入口点
intent.addCategory(Intent.CATEGORY_HOME);//*CATEGORY_HOME:随系统启动而运行
//setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //清除上一步缓存
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//*FLAG_ACTIVITY_NEW_TASK:默认的跳转类型,会重新创建一个新的Activity
startActivity(intent);
//使软件回到手机开机默认显示的桌面界面
基础知识
判断字符串是否为空
if (TextUtils.isEmpty(str)) {//判断字符串为空
return null;
}